From 05eaf783b270ec5cd901704c5e16b6201de7a9e4 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Thu, 20 Aug 2026 07:48:02 +0000 Subject: [PATCH 001/223] 8390212: (dc) On AIX, DatagramChannel.join can join IPv4 multicast group with IPv6 socket Reviewed-by: alanb, mbaesken, mdoerr --- src/java.base/unix/native/libnio/ch/Net.c | 20 +++++++++++++++++--- test/jdk/ProblemList.txt | 5 +---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c index 2b281f9a2048..fe0866027f2f 100644 --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -96,6 +96,11 @@ static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, #ifdef _AIX +static jboolean isIPv4MappedGroup(struct group_source_req *req) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&req->gsr_group; + return IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ? JNI_TRUE : JNI_FALSE; +} + /* * Checks whether or not "socket extensions for multicast source filters" is supported. * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise @@ -225,7 +230,7 @@ Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl) JNIEXPORT jboolean JNICALL Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) { -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(_AIX) /* IPv6 sockets can join IPv4 multicast groups */ return JNI_TRUE; #else @@ -237,7 +242,7 @@ Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) JNIEXPORT jboolean JNICALL Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) { -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(_AIX) /* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */ return JNI_TRUE; #else @@ -767,6 +772,11 @@ Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobjec if (n < 0) { if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; +#ifdef _AIX + // AIX rejects MCAST_*_SOURCE_GROUP for IPv4-mapped groups with EINVAL + if (source != NULL && errno == EINVAL && isIPv4MappedGroup(&req)) + return IOS_UNAVAILABLE; +#endif handleSocketErrorWithMessage(env, errno, "setsockopt failed"); } return 0; @@ -791,6 +801,11 @@ Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, j if (n < 0) { if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) return IOS_UNAVAILABLE; +#ifdef _AIX + // AIX rejects MCAST_BLOCK/UNBLOCK_SOURCE for IPv4-mapped groups with EINVAL + if (errno == EINVAL && isIPv4MappedGroup(&req)) + return IOS_UNAVAILABLE; +#endif handleSocketError(env, errno); } return 0; @@ -990,4 +1005,3 @@ Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b) int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB); return convertReturnVal(env, n, JNI_FALSE); } - diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index ecf829ad484e..1896f0231d39 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -446,17 +446,14 @@ javax/management/remote/mandatory/connection/BrokenConnectionTest.java 8262312 l java/net/DatagramSocket/DatagramSocketExample.java 8308807 aix-ppc64 java/net/DatagramSocket/DatagramSocketMulticasting.java 8308807 aix-ppc64 -java/net/MulticastSocket/B6427403.java 8308807 aix-ppc64 java/net/MulticastSocket/IPMulticastIF.java 8308807 aix-ppc64 java/net/MulticastSocket/JoinLeave.java 8308807 aix-ppc64 -java/net/MulticastSocket/MulticastAddresses.java 8308807 aix-ppc64 java/net/MulticastSocket/NoLoopbackPackets.java 7122846,8308807 macosx-all,aix-ppc64 java/net/MulticastSocket/NoSetNetworkInterface.java 8308807 aix-ppc64 -java/net/MulticastSocket/Promiscuous.java 8308807 aix-ppc64 java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8308807 aix-ppc64 java/net/MulticastSocket/SetLoopbackMode.java 7122846,8308807 macosx-all,aix-ppc64 java/net/MulticastSocket/SetOutgoingIf.java 8308807 aix-ppc64 -java/net/MulticastSocket/Test.java 7145658,8308807 macosx-all,aix-ppc64 +java/net/MulticastSocket/Test.java 7145658 macosx-all ############################################################################ From c92288eb8db0eab21773ad3a26b755d2af220105 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 20 Aug 2026 09:42:20 +0000 Subject: [PATCH 002/223] 8390299: Unify *oop type hierarchy with *oopDesc type hierarchy Reviewed-by: stefank, fbredberg --- src/hotspot/share/oops/oopsHierarchy.hpp | 77 +++++++++++++++--------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/oops/oopsHierarchy.hpp b/src/hotspot/share/oops/oopsHierarchy.hpp index 03c6850f00b0..83f2ad866138 100644 --- a/src/hotspot/share/oops/oopsHierarchy.hpp +++ b/src/hotspot/share/oops/oopsHierarchy.hpp @@ -82,6 +82,10 @@ using CheckOopFunctionPointer = void(*)(oopDesc*); extern CheckOopFunctionPointer check_oop_function; class oop { +public: + using DescType = oopDesc; + +private: oopDesc* _o; void register_oop(); @@ -125,41 +129,54 @@ struct PrimitiveConversions::Translate : public std::true_type { static Value recover(Decayed x) { return oop(x); } }; -#define DEF_OOP(type) \ - class type##OopDesc; \ - class type##Oop : public oop { \ - public: \ - type##Oop() : oop() {} \ - type##Oop(const type##Oop& o) : oop(o) {} \ - type##Oop(const oop& o) : oop(o) {} \ - type##Oop(type##OopDesc* o) : oop((oopDesc*)o) {} \ - operator type##OopDesc* () const { return (type##OopDesc*)obj(); } \ - type##OopDesc* operator->() const { \ - return (type##OopDesc*)obj(); \ - } \ - type##Oop& operator=(const type##Oop& o) { \ - oop::operator=(o); \ - return *this; \ - } \ - }; \ +#define DEF_OOP_IMPL(OopType, OopDescType, BaseOopType) \ + class OopDescType; \ + class OopType : public BaseOopType { \ + public: \ + using DescType = OopDescType; \ + OopType() : BaseOopType() {} \ + OopType(std::nullptr_t) : BaseOopType() {} \ + OopType(const OopType& o) : BaseOopType(o) {} \ + explicit OopType(const oop& o) : BaseOopType(o) {} \ + OopType(DescType* o) : BaseOopType((BaseOopType::DescType*)o) {} \ + operator DescType*() const { return (DescType*)obj(); } \ + DescType* operator->() const { return (DescType*)obj(); } \ + OopType& operator=(std::nullptr_t) { \ + BaseOopType::operator=(nullptr); \ + return *this; \ + } \ + OopType& operator=(const OopType& o) { \ + BaseOopType::operator=(o); \ + return *this; \ + } \ + OopType& operator=(const oop& o) = delete; \ + }; \ \ - template<> \ - struct PrimitiveConversions::Translate : public std::true_type { \ - typedef type##Oop Value; \ - typedef type##OopDesc* Decayed; \ + template <> \ + struct PrimitiveConversions::Translate : public std::true_type { \ + typedef OopType Value; \ + typedef OopType::DescType* Decayed; \ \ - static Decayed decay(Value x) { return (type##OopDesc*)x.obj(); } \ - static Value recover(Decayed x) { return type##Oop(x); } \ - }; + static Decayed decay(Value x) { return (OopType::DescType*)x.obj(); } \ + static Value recover(Decayed x) { return OopType(x); } \ + }; + +#define DEF_OOP_BASE(type, base) \ + DEF_OOP_IMPL(type##Oop, type##OopDesc, base##Oop) +#define DEF_OOP(type) DEF_OOP_IMPL(type##Oop, type##OopDesc, oop) DEF_OOP(instance); -DEF_OOP(inline); -DEF_OOP(stackChunk); +DEF_OOP_BASE(inline, instance); +DEF_OOP_BASE(stackChunk, instance); DEF_OOP(array); -DEF_OOP(objArray); -DEF_OOP(typeArray); -DEF_OOP(flatArray); -DEF_OOP(refArray); +DEF_OOP_BASE(objArray, array); +DEF_OOP_BASE(typeArray, array); +DEF_OOP_BASE(flatArray, objArray); +DEF_OOP_BASE(refArray, objArray); + +#undef DEF_OOP_IMPL +#undef DEF_OOP_BASE +#undef DEF_OOP #endif // CHECK_UNHANDLED_OOPS From 03530368cc7e2f1e5a15226d081eb495646b01fc Mon Sep 17 00:00:00 2001 From: Timofei Fedotov Date: Thu, 20 Aug 2026 10:55:24 +0000 Subject: [PATCH 003/223] 8389941: JvmtiEnv::FollowReferences has unreachable code in jvmtiEnv.cpp Reviewed-by: asemenov, dholmes --- src/hotspot/share/prims/jvmtiEnv.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 2bb6d994c61a..238d2a7c2c17 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1913,9 +1913,7 @@ JvmtiEnv::FollowReferences(jint heap_filter, jclass klass, jobject initial_objec return JVMTI_ERROR_NONE; } k = java_lang_Class::as_Klass(k_mirror); - if (klass == nullptr) { - return JVMTI_ERROR_INVALID_CLASS; - } + assert(k != nullptr, "k_mirror is not null and not primitive, must have a valid klass"); } if (initial_object != nullptr) { From 91c6a3319a8e3d65077ed0850f1e71b8d4e9d1cb Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Thu, 20 Aug 2026 10:58:32 +0000 Subject: [PATCH 004/223] 8388873: C2: AddHF is wrongly reassociated using AddNode::Ideal Reviewed-by: qamai, dlong --- src/hotspot/share/opto/addnode.cpp | 19 +- src/hotspot/share/opto/addnode.hpp | 27 +-- src/hotspot/share/opto/phaseX.cpp | 2 +- .../irTests/AddHFNodeIdealizationTests.java | 166 ++++++++++++++++++ 4 files changed, 190 insertions(+), 24 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/AddHFNodeIdealizationTests.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 4ac91427eef8..ebb41e552a2a 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -697,6 +697,13 @@ const Type *AddLNode::add_ring( const Type *t0, const Type *t1 ) const { } +//============================================================================= +//------------------------------Ideal------------------------------------------ +Node* AddFPNode::Ideal(PhaseGVN* phase, bool can_reshape) { + // Floating-point addition is commutative but not associative. + return commute(phase, this) ? this : nullptr; +} + //============================================================================= //------------------------------add_of_identity-------------------------------- // Check for addition of the identity @@ -724,12 +731,6 @@ const Type *AddFNode::add_ring( const Type *t0, const Type *t1 ) const { return TypeF::make( t0->getf() + t1->getf() ); } -//------------------------------Ideal------------------------------------------ -Node *AddFNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Floating point additions are not associative because of boundary conditions (infinity) - return commute(phase, this) ? this : nullptr; -} - //============================================================================= //------------------------------add_of_identity-------------------------------- // Check for addition of the identity @@ -773,12 +774,6 @@ const Type *AddDNode::add_ring( const Type *t0, const Type *t1 ) const { return TypeD::make( t0->getd() + t1->getd() ); } -//------------------------------Ideal------------------------------------------ -Node *AddDNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Floating point additions are not associative because of boundary conditions (infinity) - return commute(phase, this) ? this : nullptr; -} - //============================================================================= //------------------------------Identity--------------------------------------- diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 793eff8dd5d1..1d78a3e5a672 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -166,45 +166,51 @@ class AddLNode : public AddNode { virtual uint ideal_reg() const { return Op_RegL; } }; +//------------------------------AddFPNode-------------------------------------- +// Add 2 floats, doubles, or half-precision floats +class AddFPNode : public AddNode { +protected: + AddFPNode(Node* in1, Node* in2) : AddNode(in1, in2) {} +public: + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* Identity(PhaseGVN* phase) { return this; } +}; + //------------------------------AddFNode--------------------------------------- // Add 2 floats -class AddFNode : public AddNode { +class AddFNode : public AddFPNode { public: - AddFNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {} + AddFNode( Node *in1, Node *in2 ) : AddFPNode(in1,in2) {} virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *add_of_identity( const Type *t1, const Type *t2 ) const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeF::ZERO; } virtual const Type *bottom_type() const { return Type::FLOAT; } int max_opcode() const { return Op_MaxF; } int min_opcode() const { return Op_MinF; } - virtual Node* Identity(PhaseGVN* phase) { return this; } virtual uint ideal_reg() const { return Op_RegF; } }; //------------------------------AddDNode--------------------------------------- // Add 2 doubles -class AddDNode : public AddNode { +class AddDNode : public AddFPNode { public: - AddDNode( Node *in1, Node *in2 ) : AddNode(in1,in2) {} + AddDNode( Node *in1, Node *in2 ) : AddFPNode(in1,in2) {} virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *add_of_identity( const Type *t1, const Type *t2 ) const; virtual const Type *add_ring( const Type *, const Type * ) const; virtual const Type *add_id() const { return TypeD::ZERO; } virtual const Type *bottom_type() const { return Type::DOUBLE; } int max_opcode() const { return Op_MaxD; } int min_opcode() const { return Op_MinD; } - virtual Node* Identity(PhaseGVN* phase) { return this; } virtual uint ideal_reg() const { return Op_RegD; } }; //------------------------------AddHFNode--------------------------------------- // Add 2 half-precision floats -class AddHFNode : public AddNode { +class AddHFNode : public AddFPNode { public: - AddHFNode(Node* in1, Node* in2) : AddNode(in1,in2) {} + AddHFNode(Node* in1, Node* in2) : AddFPNode(in1, in2) {} virtual int Opcode() const; virtual const Type* add_of_identity(const Type* t1, const Type* t2) const; virtual const Type* add_ring(const Type*, const Type*) const; @@ -212,7 +218,6 @@ class AddHFNode : public AddNode { virtual const Type* bottom_type() const { return Type::HALF_FLOAT; } int max_opcode() const { return Op_MaxHF; } int min_opcode() const { return Op_MinHF; } - virtual Node* Identity(PhaseGVN* phase) { return this; } virtual uint ideal_reg() const { return Op_RegF; } }; diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 9ec0af0e1701..2aabccfc3a52 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1431,7 +1431,7 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit // } // break; // keep verifying - // AddFNode::Ideal calls "commute", which can reorder the inputs for this: + // AddFPNode::Ideal calls "commute", which can reorder the inputs for this: // Check for tight loop increments: Loop-phi of Add of loop-phi // It wants to take the phi into in(1): // 471 Phi === 435 38 390 diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AddHFNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AddHFNodeIdealizationTests.java new file mode 100644 index 000000000000..f4e71cdc7fe4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/AddHFNodeIdealizationTests.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.Verify; +import jdk.incubator.vector.Float16; +import static jdk.incubator.vector.Float16.valueOf; + +/* + * @test + * @bug 8388873 + * @summary Test that AddHFNode is not reassociated. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class AddHFNodeIdealizationTests { + + private static final Float16 SMALL = valueOf(3.0e-4f); + private static final Float16 HALF = valueOf(0.5f); + private static final Float16 ONE = valueOf(1.0f); + + private Float16 a1 = valueOf(1.0f); + private Float16 a1024 = valueOf(1024.0f); + private Float16 a2048 = valueOf(2048.0f); + private Float16 b = valueOf(1.0f); + private Float16 bHalf = valueOf(0.5f); + + private Float16 dst1; + private Float16 dst2; + private Float16 dst3; + private Float16 dst4; + private Float16 dst5; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + // Same semantics as Float16.add, but force-inlined so the ConvF2HF idealization + // can pattern-match ConvF2HF(AddF(ConvHF2F(x), ConvHF2F(y))) into AddHF. + @ForceInline + private static Float16 add(Float16 x, Float16 y) { + return valueOf(x.floatValue() + y.floatValue()); + } + + @DontCompile + private static Float16 addHF(Float16 x, Float16 y) { + // Single, rounded Float16 addition: (x + y). + return valueOf(x.floatValue() + y.floatValue()); + } + + @DontCompile + private static Float16 goldLeft(Float16 x, Float16 y, Float16 z) { + // ((x + y) + z) + return addHF(addHF(x, y), z); + } + + @DontCompile + private static Float16 goldRight(Float16 x, Float16 y, Float16 z) { + // (x + (y + z)) + return addHF(x, addHF(y, z)); + } + + @DontCompile + private static Float16 goldChain(Float16 x, Float16 c1, Float16 c2, Float16 c3) { + // (((x + c1) + c2) + c3) + return addHF(addHF(addHF(x, c1), c2), c3); + } + + // Pattern 1: "(x + c1) + c2" -> "x + (c1 + c2)" (combine constants). + + @Test + @IR(counts = {IRNode.ADD_HF, "2"}, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, "2"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public void test1() { + dst1 = add(add(a1, SMALL), SMALL); + } + + @Check(test = "test1") + public void check1() { + Verify.checkEQ(dst1, goldLeft(a1, SMALL, SMALL)); + } + + // Pattern 1 with a large operand, where the rounding difference is + // large and easy to observe: (1024 + 0.5) + 0.5. + + @Test + @IR(counts = {IRNode.ADD_HF, "2"}, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, "2"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public void test2() { + dst2 = add(add(a1024, HALF), HALF); + } + + @Check(test = "test2") + public void check2() { + Verify.checkEQ(dst2, goldLeft(a1024, HALF, HALF)); + } + + // Pattern 1, longer chain: "((x + c1) + c2) + c3". Without the fix the + // three constants collapse into one, leaving a single AddHF; with the + // fix all three additions survive. + + @Test + @IR(counts = {IRNode.ADD_HF, "3"}, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, "3"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public void test3() { + dst3 = add(add(add(a2048, ONE), ONE), ONE); + } + + @Check(test = "test3") + public void check3() { + Verify.checkEQ(dst3, goldChain(a2048, ONE, ONE, ONE)); + } + + // Pattern 2: "(x + c) + y" -> "(x + y) + c" (push constant down). + // The node count stays at two, so only the numeric result exposes the bug. + + @Test + public void test4() { + dst4 = add(add(a1024, HALF), b); + } + + @Check(test = "test4") + public void check4() { + Verify.checkEQ(dst4, goldLeft(a1024, HALF, b)); + } + + // Pattern 3: "x + (y + c)" -> "(x + y) + c" (push constant down). + + @Test + public void test5() { + dst5 = add(a1024, add(bHalf, HALF)); + } + + @Check(test = "test5") + public void check5() { + Verify.checkEQ(dst5, goldRight(a1024, bHalf, HALF)); + } +} From 19525c7986ce56fecbb8e6128b94d5f3e5a07f70 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Thu, 20 Aug 2026 12:25:21 +0000 Subject: [PATCH 005/223] 8389932: C2: Merge bits F and G in VerifyIterativeGVN together Reviewed-by: chagedorn, mchevalier, kvn --- src/hotspot/share/opto/c2_globals.hpp | 6 ++-- src/hotspot/share/opto/phaseX.cpp | 31 ++++++------------- src/hotspot/share/opto/phaseX.hpp | 22 ++++++------- .../flags/jvmFlagConstraintsCompiler.cpp | 2 +- .../compiler/c2/TestVerifyIterativeGVN.java | 4 +-- 5 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index e1216b1e9efc..2de571e324a3 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -727,10 +727,8 @@ "the IGVN worklist drains") \ \ develop(uint, VerifyIterativeGVN, 0, \ - "Verify Iterative Global Value Numbering =GFEDCBA, with:" \ - " G: verify Node::Identity return an existing node" \ - " F: verify Node::Ideal does not return nullptr if the node" \ - "hash has changed" \ + "Verify Iterative Global Value Numbering =FEDCBA, with:" \ + " F: verify IGVN method return invariants" \ " E: verify node specific invariants" \ " D: verify Node::Identity did not miss opportunities" \ " C: verify Node::Ideal did not miss opportunities" \ diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 2aabccfc3a52..77c2fd27a50e 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -686,9 +686,9 @@ Node* PhaseGVN::apply_ideal(Node* k, bool can_reshape) { } Node* PhaseGVN::apply_identity(Node* n) { - DEBUG_ONLY(uint old_unique = is_verify_Identity_return() ? C->unique() : 0;) + DEBUG_ONLY(uint old_unique = is_verify_IGVN_method_return() ? C->unique() : 0;) Node* const i = n->Identity(this); - assert(!is_verify_Identity_return() || i->_idx < old_unique, + assert(!is_verify_IGVN_method_return() || i->_idx < old_unique, "Identity() must return an existing node"); return i; } @@ -2235,18 +2235,12 @@ Node *PhaseIterGVN::transform_old(Node* n) { DEBUG_ONLY(dead_loop_check(k);) DEBUG_ONLY(bool is_new = (k->outcnt() == 0);) C->remove_modified_node(k); -#ifndef PRODUCT - uint hash_before = is_verify_Ideal_return() ? k->hash() : 0; -#endif + DEBUG_ONLY(uint hash_before = is_verify_IGVN_method_return() ? k->hash() : 0;) Node* i = apply_ideal(k, /*can_reshape=*/true); assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes"); -#ifndef PRODUCT - if (is_verify_Ideal_return()) { - assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); - } - verify_step(k); -#endif - + assert(!is_verify_IGVN_method_return() || k->outcnt() == 0 || + i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); + NOT_PRODUCT(verify_step(k);) DEBUG_ONLY(uint loop_count = 1;) if (i != nullptr) { set_progress(); @@ -2270,17 +2264,12 @@ Node *PhaseIterGVN::transform_old(Node* n) { // Try idealizing again DEBUG_ONLY(is_new = (k->outcnt() == 0);) C->remove_modified_node(k); -#ifndef PRODUCT - uint hash_before = is_verify_Ideal_return() ? k->hash() : 0; -#endif + DEBUG_ONLY(uint hash_before = is_verify_IGVN_method_return() ? k->hash() : 0;) i = apply_ideal(k, /*can_reshape=*/true); assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes"); -#ifndef PRODUCT - if (is_verify_Ideal_return()) { - assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); - } - verify_step(k); -#endif + assert(!is_verify_IGVN_method_return() || k->outcnt() == 0 || + i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); + NOT_PRODUCT(verify_step(k);) DEBUG_ONLY(loop_count++;) } diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index c6fb61ec5c96..4e706f8c4783 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -458,12 +458,12 @@ class PhaseGVN : public PhaseValues { void dump_infinite_loop_info(Node* n, const char* where); // Check for a simple dead loop when a data node references itself. void dead_loop_check(Node *n); -#endif - -#ifndef PRODUCT - static bool is_verify_Identity_return() { - // '-XX:VerifyIterativeGVN=1000000' - return ((VerifyIterativeGVN % 10'000'000) / 1'000'000) == 1; + // This checks that: + // - Identity() returns only existing nodes (GVN and IGVN). + // - Ideal() does not return nullptr if the node's hash has changed (IGVN). + static bool is_verify_IGVN_method_return() { + // '-XX:VerifyIterativeGVN=100000' + return ((VerifyIterativeGVN % 1'000'000) / 100'000) == 1; } #endif }; @@ -678,19 +678,15 @@ class PhaseIterGVN : public PhaseGVN { } static bool is_verify_Ideal() { // '-XX:VerifyIterativeGVN=100' - return ((VerifyIterativeGVN % 1000) / 100) == 1; + return ((VerifyIterativeGVN % 1'000) / 100) == 1; } static bool is_verify_Identity() { // '-XX:VerifyIterativeGVN=1000' - return ((VerifyIterativeGVN % 10000) / 1000) == 1; + return ((VerifyIterativeGVN % 10'000) / 1'000) == 1; } static bool is_verify_invariants() { // '-XX:VerifyIterativeGVN=10000' - return ((VerifyIterativeGVN % 100000) / 10000) == 1; - } - static bool is_verify_Ideal_return() { - // '-XX:VerifyIterativeGVN=100000' - return ((VerifyIterativeGVN % 1000000) / 100000) == 1; + return ((VerifyIterativeGVN % 100'000) / 10'000) == 1; } protected: // Sub-quadratic implementation of '-XX:VerifyIterativeGVN=1' (Use-Def verification). diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index d48bc1e93a53..24d55c2d52d9 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -329,7 +329,7 @@ JVMFlag::Error TypeProfileLevelConstraintFunc(uint value, bool verbose) { } JVMFlag::Error VerifyIterativeGVNConstraintFunc(uint value, bool verbose) { - const int max_modes = 7; + const int max_modes = 6; uint original_value = value; for (int i = 0; i < max_modes; i++) { if (value % 10 > 1) { diff --git a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java index be8fbc79d0bc..d9340beaaf47 100644 --- a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java +++ b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java @@ -25,9 +25,9 @@ * @test * @bug 8238756 8351889 * @requires vm.debug == true & vm.flavor == "server" - * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=1111111 in debug builds. + * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=111111 in debug builds. * - * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=1111111 compiler.c2.TestVerifyIterativeGVN + * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=111111 compiler.c2.TestVerifyIterativeGVN */ package compiler.c2; From b0823242c7021681868b6167748dcaf5abf9f43a Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Thu, 20 Aug 2026 12:39:17 +0000 Subject: [PATCH 006/223] 8372384: Remove unused local variable in MacroAssembler::sha512_update_sha_state on PPC Reviewed-by: rrich, amitkumar --- src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp index bdf2d8d268ac..c7f9544be11f 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc_sha.cpp @@ -613,7 +613,6 @@ void MacroAssembler::sha512_update_sha_state(const Register state, VectorRegister ini_e = VR14; VectorRegister ini_g = VR16; static const VectorRegister inis[] = {ini_a, ini_c, ini_e, ini_g}; - static const int total_inis = sizeof(inis)/sizeof(VectorRegister); Label state_save_aligned, after_state_save_aligned; From 7bc01544236d8e6e2d3d0b9d72e4c9e736b57c62 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 20 Aug 2026 12:39:54 +0000 Subject: [PATCH 007/223] 8390451: [Valhalla] Array re-materialization loses properties Reviewed-by: qamai, fparain, jsjolen --- src/hotspot/share/ci/ciObjArrayKlass.cpp | 18 +++++--- src/hotspot/share/ci/ciObjArrayKlass.hpp | 8 ++-- src/hotspot/share/oops/arrayKlass.hpp | 40 ++++++++++++++++- src/hotspot/share/oops/objArrayKlass.hpp | 2 +- src/hotspot/share/opto/output.cpp | 36 ++++++++------- src/hotspot/share/opto/type.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 5 ++- .../inlinetypes/TestReferenceArrayClone.java | 45 +++++++++++++++---- 8 files changed, 119 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/ci/ciObjArrayKlass.cpp b/src/hotspot/share/ci/ciObjArrayKlass.cpp index a90b23b558d0..1aa8b398ea49 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.cpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,8 @@ ciSymbol* ciObjArrayKlass::construct_array_name(ciSymbol* element_name, // ciObjArrayKlass::make_impl // // Implementation of make. -ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { +ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_type, bool null_free, + bool atomic, bool force_ref_layout) { if (element_klass->is_loaded()) { EXCEPTION_CONTEXT; // The element klass is loaded @@ -158,13 +159,19 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined .with_null_restricted(null_free) .with_non_atomic(!atomic); - array = ObjArrayKlass::cast(array)->klass_with_properties(props, THREAD); + if (force_ref_layout) { + const ArrayDescription description(Klass::RefArrayKlassKind, props, LayoutKind::REFERENCE); + array = ObjArrayKlass::cast(array)->klass_from_description(description, THREAD); + } else { + array = ObjArrayKlass::cast(array)->klass_with_properties(props, THREAD); + } if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; CURRENT_THREAD_ENV->record_out_of_memory_failure(); return ciEnv::unloaded_ciobjarrayklass(); } assert(array != nullptr, "klass_with_properties should return a klass or throw"); + assert(!force_ref_layout || array->is_refArray_klass(), "must be a reference array klass"); if (array->is_flatArray_klass()) { return CURRENT_THREAD_ENV->get_flat_array_klass(array); } else { @@ -186,8 +193,9 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined // ciObjArrayKlass::make // // Make an array klass corresponding to the specified primitive type. -ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { - GUARDED_VM_ENTRY(return make_impl(element_klass, refined_type, null_free, atomic);) +ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, bool refined_type, bool null_free, + bool atomic, bool force_ref_layout) { + GUARDED_VM_ENTRY(return make_impl(element_klass, refined_type, null_free, atomic, force_ref_layout);) } ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, int dims) { diff --git a/src/hotspot/share/ci/ciObjArrayKlass.hpp b/src/hotspot/share/ci/ciObjArrayKlass.hpp index b79e65afe8da..ddea7278ec8c 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.hpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,8 @@ class ciObjArrayKlass : public ciArrayKlass { return ObjArrayKlass::cast(get_Klass()); } - static ciObjArrayKlass* make_impl(ciKlass* element_klass, bool refined_type = false, bool null_free = false, bool atomic = true); + static ciObjArrayKlass* make_impl(ciKlass* element_klass, bool refined_type = false, bool null_free = false, + bool atomic = true, bool force_reference_layout = false); static ciSymbol* construct_array_name(ciSymbol* element_name, int dimension); @@ -69,7 +70,8 @@ class ciObjArrayKlass : public ciArrayKlass { // What kind of ciObject is this? bool is_obj_array_klass() const { return true; } - static ciObjArrayKlass* make(ciKlass* element_klass, bool refined_type = true, bool null_free = false, bool atomic = true); + static ciObjArrayKlass* make(ciKlass* element_klass, bool refined_type = true, bool null_free = false, + bool atomic = true, bool force_ref_layout = false); static ciObjArrayKlass* make(ciKlass* element_klass, int dims); virtual ciKlass* exact_klass(); diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index 7144818246e4..a9fa993e1b68 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -152,6 +152,20 @@ class ArrayKlass: public Klass { }; class ArrayDescription : public StackObj { + // Layout for uint32_t encoding + // + // 31 24 23 16 15 0 + // +----------------+----------------+-----------------------------+ + // | KlassKind | LayoutKind | ArrayProperties | + // +----------------+----------------+-----------------------------+ + // 8 bits 8 bits 16 bits + static constexpr uint32_t _layout_kind_shift = 16; + static constexpr uint32_t _kind_shift = 24; + + static constexpr uint32_t _properties_mask = (1u << _layout_kind_shift) - 1; + static constexpr uint32_t _layout_kind_mask = (1u << (_kind_shift - _layout_kind_shift)) - 1; + static constexpr uint32_t _kind_mask = (1u << (32 - _kind_shift)) - 1; + public: Klass::KlassKind _kind; ArrayProperties _properties; @@ -168,6 +182,30 @@ class ArrayDescription : public StackObj { const bool non_atomic = lk != LayoutKind::REFERENCE && !LayoutKindHelper::is_atomic_flat(lk); _properties = p.with_non_atomic(non_atomic); } - }; + + uint32_t value() const { + assert((_properties.value() & ~_properties_mask) == 0, "array properties do not fit into encoding"); + + uint32_t layout_kind_value = static_cast(_layout_kind); + assert((layout_kind_value & ~_layout_kind_mask) == 0, "layout kind does not fit into encoding"); + + uint32_t kind_value = static_cast(_kind); + assert((kind_value & ~_kind_mask) == 0, "klass kind does not fit into encoding"); + + return _properties.value() | (layout_kind_value << _layout_kind_shift) | (kind_value << _kind_shift); + } + + static ArrayDescription from_value(uint32_t value) { + ArrayProperties properties(value & _properties_mask); + + uint32_t layout_kind_value = (value >> _layout_kind_shift) & _layout_kind_mask; + LayoutKind layout_kind = static_cast(layout_kind_value); + + uint32_t kind_value = (value >> _kind_shift) & _kind_mask; + Klass::KlassKind kind = static_cast(kind_value); + + return ArrayDescription(kind, properties, layout_kind); + } +}; #endif // SHARE_OOPS_ARRAYKLASS_HPP diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 16b3170fdda2..934eedcbf6a6 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -50,7 +50,6 @@ class ObjArrayKlass : public ArrayKlass { static ArrayDescription array_layout_selection(Klass* element, ArrayProperties properties); ObjArrayKlass* allocate_klass_from_description(ArrayDescription ad, TRAPS); - ObjArrayKlass* klass_from_description(ArrayDescription adesc, TRAPS); inline ObjArrayKlass* next_refined_array_klass_acquire() const; inline void release_set_next_refined_klass(ObjArrayKlass* ak); @@ -74,6 +73,7 @@ class ObjArrayKlass : public ArrayKlass { Klass* element_klass() const { return _element_klass; } ObjArrayKlass* klass_with_properties(ArrayProperties props, TRAPS); + ObjArrayKlass* klass_from_description(ArrayDescription adesc, TRAPS); ObjArrayKlass* next_refined_array_klass() const { return _next_refined_array_klass; } bool find_refined_array_klass(ObjArrayKlass* k); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 8abe61f698fd..45a6f206d703 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -23,6 +23,7 @@ */ #include "asm/assembler.inline.hpp" +#include "ci/ciFlatArrayKlass.hpp" #include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "code/debugInfo.hpp" @@ -35,6 +36,7 @@ #include "gc/shared/c2/barrierSetC2.hpp" #include "gc/shared/gc_globals.hpp" #include "memory/allocation.hpp" +#include "oops/arrayKlass.hpp" #include "opto/ad.hpp" #include "opto/block.hpp" #include "opto/c2_MacroAssembler.hpp" @@ -745,6 +747,22 @@ void PhaseOutput::set_sv_for_object_node(GrowableArray *objs, objs->append(sv); } +static jint array_description_value(const TypeAryPtr* ary_type) { + ciArrayKlass* array_klass = ary_type->exact_klass()->as_array_klass(); + const bool is_element_inline = array_klass->element_klass()->is_inlinetype(); + ArrayProperties properties = ArrayProperties::Default() + .with_null_restricted(is_element_inline && array_klass->is_elem_null_free()) + .with_non_atomic(is_element_inline && !array_klass->is_elem_atomic()); + + LayoutKind layout_kind = LayoutKind::REFERENCE; + Klass::KlassKind kind = Klass::RefArrayKlassKind; + if (ary_type->is_flat()) { + layout_kind = array_klass->as_flat_array_klass()->layout_kind(); + kind = Klass::FlatArrayKlassKind; + } + return (jint)ArrayDescription(kind, properties, layout_kind).value(); +} + void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, GrowableArray *array, @@ -792,14 +810,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, } } if (cik->is_array_klass() && !cik->is_type_array_klass()) { - ciArrayKlass* ciak = cik->as_array_klass(); - const bool is_element_inline = ciak->element_klass()->is_inlinetype(); - - const ArrayProperties props = ArrayProperties::Default() - .with_null_restricted(is_element_inline && ciak->is_elem_null_free()) - .with_non_atomic(is_element_inline && !ciak->is_elem_atomic()); - - properties = new ConstantIntValue((jint)props.value()); + properties = new ConstantIntValue(array_description_value(t->is_aryptr())); } sv = new ObjectValue(spobj->_idx, new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()), true, properties); @@ -1143,14 +1154,7 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { assert(!cik->is_inlinetype(), "Synchronization on value object?"); ScopeValue* properties = nullptr; if (cik->is_array_klass() && !cik->is_type_array_klass()) { - ciArrayKlass* ciak = cik->as_array_klass(); - const bool is_element_inline = ciak->element_klass()->is_inlinetype(); - - const ArrayProperties props = ArrayProperties::Default() - .with_null_restricted(is_element_inline && ciak->is_elem_null_free()) - .with_non_atomic(is_element_inline && !ciak->is_elem_atomic()); - - properties = new ConstantIntValue((jint)props.value()); + properties = new ConstantIntValue(array_description_value(t->is_aryptr())); } ObjectValue* sv = new ObjectValue(spobj->_idx, new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()), true, properties); diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 09a4237ab0bc..ec13d305228d 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -7350,7 +7350,7 @@ ciKlass* TypeAryKlassPtr::exact_klass_helper() const { return nullptr; } assert(!k->is_array_klass() || !k->as_array_klass()->is_refined(), "no mechanism to create an array of refined arrays %s", k->name()->as_utf8()); - k = ciArrayKlass::make(k, is_null_free(), is_atomic(), _refined_type); + k = ciObjArrayKlass::make(k, _refined_type, is_null_free(), is_atomic(), is_not_flat()); return k; } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index bcf86d0f6a37..a0d304fe1584 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -310,8 +310,9 @@ static Klass* get_refined_array_klass(Klass* k, frame* fr, RegisterMap* map, Obj assert(k->is_unrefined_objArray_klass(), "Expected unrefined array klass"); nmethod* nm = fr->cb()->as_nmethod_or_null(); assert(sv->has_properties(), "Property information is missing"); - ArrayProperties props(checked_cast(StackValue::create_stack_value(fr, map, sv->properties())->get_jint())); - k = ObjArrayKlass::cast(k)->klass_with_properties(props, THREAD); + uint32_t value = checked_cast(StackValue::create_stack_value(fr, map, sv->properties())->get_jint()); + ArrayDescription description = ArrayDescription::from_value(value); + k = ObjArrayKlass::cast(k)->klass_from_description(description, THREAD); } return k; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java index 681eb5687b0f..df5f4878090d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java @@ -23,15 +23,18 @@ /* * @test - * @summary Verify that clone preserves the layout of reference arrays. - * @bug 8388256 + * @summary Verify that C2 preserves the layout of reference array clones. + * @bug 8388256 8390451 * @requires vm.compiler2.enabled * @library /test/lib / * @enablePreview * @modules java.base/jdk.internal.value - * @run main ${test.main.class} + * @run main/othervm -Xbatch ${test.main.class} * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:-UseTLAB - * -XX:CompileCommand=compileonly,${test.main.class}::testClone + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:-UseTLAB -XX:-DoEscapeAnalysis + * -XX:CompileCommand=compileonly,${test.main.class}::test* * ${test.main.class} */ @@ -41,17 +44,43 @@ import jdk.test.lib.Asserts; public class TestReferenceArrayClone { + static final Integer[] ARRAY = (Integer[])ValueClass.newReferenceArray(Integer.class, 1); + static Integer[] testClone(Integer[] a) { return a.clone(); } - public static void main(String[] args) { - Integer[] array = (Integer[])ValueClass.newReferenceArray(Integer.class, 1); + static void testDeopt(boolean deopt) { + Integer[] array = (Integer[])ValueClass.newReferenceArray(Integer.class, 1).clone(); array[0] = 42; - array = testClone(array); - Asserts.assertEQ(array[0], 42, "unexpected element"); + if (deopt) { + verify(array); + } + } + + static void testDeoptClone(boolean deopt) { + Integer[] clone = ARRAY.clone(); + if (deopt) { + verify(clone); + } + } + + static void verify(Integer[] array) { Asserts.assertFalse(ValueClass.isFlatArray(array), "should not be flat"); Asserts.assertFalse(ValueClass.isNullRestrictedArray(array), "should not be null-restricted"); Asserts.assertTrue(ValueClass.isAtomicArray(array), "should be atomic"); + Asserts.assertEQ(array[0], 42, "unexpected element"); + } + + public static void main(String[] args) { + ARRAY[0] = 42; + verify(testClone(ARRAY)); + + for (int i = 0; i < 20_000; i++) { + testDeopt(false); + testDeoptClone(false); + } + testDeopt(true); + testDeoptClone(true); } } From 30e5083ee362b42e3359748fcd93291fa384483e Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 20 Aug 2026 15:44:21 +0000 Subject: [PATCH 008/223] 8387539: Shenandoah: Nonsensical values for consumption acceleration Reviewed-by: kdnilsen, xpeng, ruili, shade --- .../shenandoahAdaptiveHeuristics.cpp | 24 +++- .../share/gc/shenandoah/shenandoahUtils.hpp | 31 +++++- .../gc/shenandoah/test_shenandoahUtils.cpp | 104 ++++++++++++++++++ 3 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/gtest/gc/shenandoah/test_shenandoahUtils.cpp diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 4cd8af1370d0..dd259497d341 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -30,6 +30,7 @@ #include "gc/shenandoah/shenandoahAllocRate.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" @@ -40,6 +41,7 @@ #define PROPERFMT_F "%.1f %s" #define PROPERFMT_F_ARGS(s) byte_size_in_proper_unit(s), proper_unit_for_byte_size(s) +#define PROPERFMTARGS_SIGNED(s) (s).value, (s).unit // These are used to decide if we want to make any adjustments at all // at the end of a successful concurrent cycle. @@ -379,21 +381,24 @@ bool ShenandoahAdaptiveHeuristics::trigger_average_allocation_rate(const Shenand // a sample period of roughly 15 ms, spanning approximately 120 ms of execution. bool ShenandoahAdaptiveHeuristics::trigger_accelerating_allocation_rate(const ShenandoahAnticipatedConsumption& rate, const size_t allocatable_bytes) { if (rate.momentary_consumption() > allocatable_bytes) { + const ShenandoahSignedSize momentary_rate = ShenandoahSignedSize::get(rate.momentary_rate()); assert(rate.accelerated_consumption() == 0, "Momentary trigger is meant to exclude acceleration trigger"); log_trigger("Momentary spike consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " "current rate (" PROPERFMT_F "/s) for anticipated GC duration (%.2f ms)", PROPERFMTARGS(rate.momentary_consumption()), PROPERFMTARGS(allocatable_bytes), - PROPERFMT_F_ARGS(rate.momentary_rate()), rate.duration_seconds() * 1000); + PROPERFMTARGS_SIGNED(momentary_rate), rate.duration_seconds() * 1000); accept_trigger_with_type(RATE); return true; } if (rate.accelerated_consumption() > allocatable_bytes) { + const ShenandoahSignedSize predicted_rate = ShenandoahSignedSize::get(rate.predicted_rate()); + const ShenandoahSignedSize acceleration = ShenandoahSignedSize::get(rate.acceleration()); assert(rate.momentary_consumption() == 0, "Acceleration trigger is meant to exclude momentary trigger"); log_trigger("Accelerated consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " "current rate (" PROPERFMT_F "/s) with acceleration (" PROPERFMT_F "/s/s) for anticipated GC duration (%.2f ms)", PROPERFMTARGS(rate.accelerated_consumption()), PROPERFMTARGS(allocatable_bytes), - PROPERFMT_F_ARGS(rate.predicted_rate()), PROPERFMT_F_ARGS(rate.acceleration()), rate.duration_seconds() * 1000); + PROPERFMTARGS_SIGNED(predicted_rate), PROPERFMTARGS_SIGNED(acceleration), rate.duration_seconds() * 1000); accept_trigger_with_type(RATE); return true; } @@ -404,15 +409,21 @@ bool ShenandoahAdaptiveHeuristics::trigger_accelerating_allocation_rate(const Sh void ShenandoahAdaptiveHeuristics::maybe_log_rate_trigger_parameters(const ShenandoahAnticipatedConsumption &consumption, size_t allocatable_bytes) const { if (log_is_enabled(Debug, gc, sampling)) { + const ShenandoahSignedSize momentary_rate = ShenandoahSignedSize::get(consumption.momentary_rate()); + const ShenandoahSignedSize predicted_rate = ShenandoahSignedSize::get(consumption.predicted_rate()); + const ShenandoahSignedSize baseline_rate = ShenandoahSignedSize::get(consumption.baseline_rate()); + const ShenandoahSignedSize acceleration = ShenandoahSignedSize::get(consumption.acceleration()); log_debug(gc, sampling)( "%s: Anticipated cycle duration: %.3fs, head room: " PROPERFMT ", margin of error: %.3f " "Baseline consumption: " PROPERFMT ", Baseline rate: " PROPERFMT_F "/s, " "Momentary consumption: " PROPERFMT ", Momentary rate: " PROPERFMT_F "/s, " - "Accelerated consumption: " PROPERFMT ", Predicted rate: " PROPERFMT_F "/s, Acceleration: %.3f", + "Accelerated consumption: " PROPERFMT ", Predicted rate: " PROPERFMT_F "/s, " + "Acceleration: " PROPERFMT_F "/s", _space_info->name(), consumption.duration_seconds(), PROPERFMTARGS(allocatable_bytes), _margin_of_error_sd, - PROPERFMTARGS(consumption.baseline_consumption()), PROPERFMT_F_ARGS(consumption.baseline_rate()), - PROPERFMTARGS(consumption.momentary_consumption()), PROPERFMT_F_ARGS(consumption.momentary_rate()), - PROPERFMTARGS(consumption.accelerated_consumption()), PROPERFMT_F_ARGS(consumption.predicted_rate()), consumption.acceleration() + PROPERFMTARGS(consumption.baseline_consumption()), PROPERFMTARGS_SIGNED(baseline_rate), + PROPERFMTARGS(consumption.momentary_consumption()), PROPERFMTARGS_SIGNED(momentary_rate), + PROPERFMTARGS(consumption.accelerated_consumption()), PROPERFMTARGS_SIGNED(predicted_rate), + PROPERFMTARGS_SIGNED(acceleration) ); } } @@ -428,3 +439,4 @@ size_t ShenandoahAdaptiveHeuristics::min_free_threshold(size_t capacity) const { #undef PROPERFMT_F #undef PROPERFMT_F_ARGS +#undef PROPERFMTARGS_SIGNED diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index e9761ebeb863..7b49854e16ca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -30,16 +30,17 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/workerThread.hpp" +#include "gc/shenandoah/shenandoahGenerationType.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" -#include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" #include "services/memoryService.hpp" +#include "utilities/globalDefinitions.hpp" #include #include @@ -257,6 +258,32 @@ inline size_t shenandoah_safe_size_cast(const double d) { return static_cast(d); } +// Convert a possibly signed double into a smaller number with appropriate engineering units. +struct ShenandoahSignedSize { + const double value; + const char* unit; + static ShenandoahSignedSize get(double v) { + if (!std::isfinite(v)) { + return { v, "B" }; + } + + const double magnitude = fabsd(v); + + if (magnitude >= 100.0 * G) { + return { std::copysign(magnitude / G, v), "G" }; + } + + if (magnitude >= 100.0 * M) { + return { std::copysign(magnitude / M, v), "M" }; + } + + if (magnitude >= 100.0 * K) { + return { std::copysign(magnitude / K, v), "K" }; + } + + return { std::copysign(magnitude, v), "B" }; + } +}; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahUtils.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahUtils.cpp new file mode 100644 index 000000000000..22524f68d269 --- /dev/null +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahUtils.cpp @@ -0,0 +1,104 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/shenandoah/shenandoahUtils.hpp" +#include "utilities/globalDefinitions.hpp" + +#include +#include + +#include "unittest.hpp" + +static void test_units(double value, double expected_value, const char* expected_unit) { + ShenandoahSignedSize s = ShenandoahSignedSize::get(value); + EXPECT_DOUBLE_EQ(expected_value, s.value); + EXPECT_STREQ(expected_unit, s.unit); +} + +TEST(ShenandoahUtilsTest, format_byte_double) { + test_units(1024.0, 1024.0, "B"); + test_units(-1024.0, -1024.0, "B"); + test_units(1024.5, 1024.5, "B"); + test_units(-1024.5, -1024.5, "B"); +} + +TEST(ShenandoahUtilsTest, format_kilo_double) { + test_units(900.0 * K, 900.0, "K"); + test_units(-900.0 * K, -900.0, "K"); + test_units(900.1 * K, 900.1, "K"); + test_units(-900.1 * K, -900.1, "K"); +} + +TEST(ShenandoahUtilsTest, format_mega_double) { + test_units(900.0 * M, 900.0, "M"); + test_units(-900.0 * M, -900.0, "M"); + test_units(900.1 * M, 900.1, "M"); + test_units(-900.1 * M, -900.1, "M"); +} + +TEST(ShenandoahUtilsTest, format_giga_double) { + test_units(900.0 * G, 900.0, "G"); + test_units(-900.0 * G, -900.0, "G"); + test_units(900.1 * G, 900.1, "G"); + test_units(-900.1 * G, -900.1, "G"); +} + +TEST(ShenandoahUtilsTest, format_negative_zero_double) { + ShenandoahSignedSize s = ShenandoahSignedSize::get(-0.0); + EXPECT_DOUBLE_EQ(0.0, s.value); + EXPECT_STREQ("B", s.unit); + EXPECT_TRUE(std::signbit(s.value)); +} + +TEST(ShenandoahUtilsTest, format_infinite_double) { + const double inf = std::numeric_limits::infinity(); + ShenandoahSignedSize s = ShenandoahSignedSize::get(inf); + EXPECT_EQ(s.value, inf); + EXPECT_TRUE(std::isinf(s.value)); + EXPECT_STREQ("B", s.unit); +} + +TEST(ShenandoahUtilsTest, format_negative_infinite_double) { + const double ninf = -std::numeric_limits::infinity(); + ShenandoahSignedSize s = ShenandoahSignedSize::get(ninf); + EXPECT_EQ(s.value, ninf); + EXPECT_TRUE(std::isinf(s.value)); + EXPECT_STREQ("B", s.unit); +} + +TEST(ShenandoahUtilsTest, format_nan_double) { + ShenandoahSignedSize s = ShenandoahSignedSize::get(std::numeric_limits::quiet_NaN()); + EXPECT_TRUE(std::isnan(s.value)); + EXPECT_STREQ("B", s.unit); +} + +TEST(ShenandoahUtilsTest, format_unit_boundaries) { + // nextafter returns the next representable value of first argument in the direction of the second + EXPECT_STREQ("B", ShenandoahSignedSize::get(std::nextafter(100.0 * K, 0.0)).unit); + EXPECT_STREQ("K", ShenandoahSignedSize::get(std::nextafter(100.0 * M, 0.0)).unit); + EXPECT_STREQ("M", ShenandoahSignedSize::get(std::nextafter(100.0 * G, 0.0)).unit); + EXPECT_STREQ("B", ShenandoahSignedSize::get(std::nextafter(-100.0 * K, 0.0)).unit); + EXPECT_STREQ("K", ShenandoahSignedSize::get(std::nextafter(-100.0 * M, 0.0)).unit); + EXPECT_STREQ("M", ShenandoahSignedSize::get(std::nextafter(-100.0 * G, 0.0)).unit); +} From 855b7430c485e498489d1cdc62048217e213d020 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 20 Aug 2026 16:08:55 +0000 Subject: [PATCH 009/223] 8387469: Shenandoah: GC logs should show end-to-end cycle time and heap used updates Reviewed-by: wkemper, kdnilsen, xpeng --- .../heuristics/shenandoahGlobalHeuristics.cpp | 4 +- .../heuristics/shenandoahOldHeuristics.cpp | 10 ++-- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 51 ++++++++++--------- .../gc/shenandoah/shenandoahControlThread.cpp | 4 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 2 +- .../gc/shenandoah/shenandoahGeneration.cpp | 2 +- .../shenandoahGenerationalControlThread.cpp | 4 +- .../shenandoah/shenandoahGenerationalHeap.cpp | 2 +- .../share/gc/shenandoah/shenandoahOldGC.cpp | 3 ++ .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 +- .../gc/shenandoah/shenandoahPhaseTimings.hpp | 1 + .../share/gc/shenandoah/shenandoahUtils.cpp | 22 ++++++++ .../share/gc/shenandoah/shenandoahUtils.hpp | 30 ++++++++++- 13 files changed, 97 insertions(+), 40 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index d9f3bdee8282..5c07fcb6b59f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -226,14 +226,14 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti size_t delta_bytes = budget.young_evac.reserve() - heap->young_generation()->get_evacuation_reserve(); size_t delta_regions = delta_bytes / region_size_bytes; size_t regions_to_transfer = MIN2(unaffiliated_old_regions, delta_regions); - log_info(gc)("Global GC moves %zu unaffiliated regions from old collector to young collector reserves", regions_to_transfer); + log_info(gc, ergo)("Global GC moves %zu unaffiliated regions from old collector to young collector reserves", regions_to_transfer); ssize_t negated_regions = -regions_to_transfer; heap->free_set()->move_unaffiliated_regions_from_collector_to_old_collector(negated_regions); } else if (heap->young_generation()->get_evacuation_reserve() > budget.young_evac.reserve()) { size_t delta_bytes = heap->young_generation()->get_evacuation_reserve() - budget.young_evac.reserve(); size_t delta_regions = delta_bytes / region_size_bytes; size_t regions_to_transfer = MIN2(unaffiliated_young_regions, delta_regions); - log_info(gc)("Global GC moves %zu unaffiliated regions from young collector to old collector reserves", regions_to_transfer); + log_info(gc, ergo)("Global GC moves %zu unaffiliated regions from young collector to old collector reserves", regions_to_transfer); heap->free_set()->move_unaffiliated_regions_from_collector_to_old_collector(regions_to_transfer); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 333451a81258..44bc683cbd6c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -321,7 +321,7 @@ bool ShenandoahOldHeuristics::finalize_mixed_evacs() { } decrease_unprocessed_old_collection_candidates_live_memory(_evacuated_old_bytes); if (_included_old_regions > 0) { - log_info(gc)("Old-gen mixed evac (%zu regions, evacuating %zu%s, reclaiming: %zu%s)", + log_info(gc, ergo)("Old-gen mixed evac (%zu regions, evacuating %zu%s, reclaiming: %zu%s)", _included_old_regions, byte_size_in_proper_unit(_evacuated_old_bytes), proper_unit_for_byte_size(_evacuated_old_bytes), byte_size_in_proper_unit(_collected_old_bytes), proper_unit_for_byte_size(_collected_old_bytes)); @@ -339,10 +339,10 @@ bool ShenandoahOldHeuristics::finalize_mixed_evacs() { // if they are all pinned we transition to a state that will allow us to make these uncollected // (pinned) regions parsable. if (all_candidates_are_pinned()) { - log_info(gc)("All candidate regions " UINT32_FORMAT " are pinned", unprocessed_old_collection_candidates()); + log_info(gc, ergo)("All candidate regions " UINT32_FORMAT " are pinned", unprocessed_old_collection_candidates()); _old_generation->abandon_mixed_evacuations(); } else { - log_info(gc)("No regions selected for mixed collection. " + log_info(gc, ergo)("No regions selected for mixed collection. " "Old evacuation budget: " PROPERFMT ", Next candidate: " UINT32_FORMAT ", Last candidate: " UINT32_FORMAT, PROPERFMTARGS(_old_evacuation_reserve), _next_old_collection_candidate, _last_old_collection_candidate); @@ -382,7 +382,7 @@ bool ShenandoahOldHeuristics::top_off_collection_set(ShenandoahCollectionSet* co regions_for_old_expansion = 0; } if (regions_for_old_expansion > 0) { - log_info(gc)("Augmenting old-gen evacuation budget from unexpended young-generation reserve by %zu regions", + log_info(gc, ergo)("Augmenting old-gen evacuation budget from unexpended young-generation reserve by %zu regions", regions_for_old_expansion); add_regions_to_old = regions_for_old_expansion; size_t budget_supplement = region_size_bytes * regions_for_old_expansion; @@ -844,7 +844,7 @@ void ShenandoahOldHeuristics::adjust_old_garbage_threshold() { } else { _old_garbage_threshold = ShenandoahOldGarbageThreshold - adjustment_potential / 3; } - log_info(gc)("Adjusting old garbage threshold to %lu because Old Generation used regions represents %lu%% of heap", + log_info(gc, ergo)("Adjusting old garbage threshold to %lu because Old Generation used regions represents %lu%% of heap", _old_garbage_threshold, percent_used); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index fe7e5211e0a6..09ca7e4315d4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -106,7 +106,7 @@ ShenandoahGC::ShenandoahDegenPoint ShenandoahConcurrentGC::degen_point() const { void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap* const heap) { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent init update refs", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs_prepare); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs_prepare); EventMark em("%s", msg); heap->try_inject_pin(); @@ -118,7 +118,7 @@ void ShenandoahConcurrentGC::entry_update_card_table() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update cards", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_card_table); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_update_card_table); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -137,6 +137,9 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { _generation->ref_processor()->set_soft_reference_policy( GCCause::should_clear_all_soft_refs(cause)); + SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent GC", ""); + ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_gc, /* log_heap_usage = */ true); + ShenandoahBreakpointGCScope breakpoint_gc_scope(cause); // Reset for upcoming marking @@ -295,7 +298,7 @@ void ShenandoahConcurrentGC::entry_complete_abbreviated_cycle() { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent complete abbreviated cycle", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::complete_abbreviated); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::complete_abbreviated); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -379,7 +382,7 @@ void ShenandoahConcurrentGC::entry_init_mark() { assert(!heap->has_forwarded_objects(), "Should not have forwarded objects here"); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Mark", ""); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_mark); + ShenandoahPauseSubphase gc_phase(msg, ShenandoahPhaseTimings::init_mark); EventMark em("%s", msg); ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(), @@ -395,7 +398,7 @@ void ShenandoahConcurrentGC::entry_final_mark() { "Should not have forwarded objects during final mark, unless old gen concurrent mark is running"); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Mark", ""); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_mark); + ShenandoahPauseSubphase gc_phase(msg, ShenandoahPhaseTimings::final_mark); EventMark em("%s", msg); ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(), @@ -407,7 +410,7 @@ void ShenandoahConcurrentGC::entry_final_mark() { void ShenandoahConcurrentGC::entry_init_update_refs() { SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Init Update Refs", ""); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_update_refs); + ShenandoahPauseSubphase gc_phase(msg, ShenandoahPhaseTimings::init_update_refs); EventMark em("%s", msg); // No workers used in this phase, no setup required @@ -416,7 +419,7 @@ void ShenandoahConcurrentGC::entry_init_update_refs() { void ShenandoahConcurrentGC::entry_final_update_refs() { SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Final Update Refs", ""); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_update_refs); + ShenandoahPauseSubphase gc_phase(msg, ShenandoahPhaseTimings::final_update_refs); EventMark em("%s", msg); ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(), @@ -428,7 +431,7 @@ void ShenandoahConcurrentGC::entry_final_update_refs() { void ShenandoahConcurrentGC::entry_final_verify() { SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Pause Verify Final", ""); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify); + ShenandoahPauseSubphase gc_phase(msg, ShenandoahPhaseTimings::final_verify); EventMark em("%s", msg); op_verify_final(); @@ -442,7 +445,7 @@ void ShenandoahConcurrentGC::entry_reset() { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); { SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_reset); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -458,7 +461,7 @@ void ShenandoahConcurrentGC::entry_scan_remembered_set() { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent remembered set scanning", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::init_scan_rset); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::init_scan_rset); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -474,7 +477,7 @@ void ShenandoahConcurrentGC::entry_mark_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_mark_roots); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -492,7 +495,7 @@ void ShenandoahConcurrentGC::entry_mark() { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent marking", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_mark); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_mark); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -507,7 +510,7 @@ void ShenandoahConcurrentGC::entry_mark() { void ShenandoahConcurrentGC::entry_thread_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent thread roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_thread_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_thread_roots); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -522,7 +525,7 @@ void ShenandoahConcurrentGC::entry_thread_roots() { void ShenandoahConcurrentGC::entry_weak_refs() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak references", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_refs); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_refs); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -538,7 +541,7 @@ void ShenandoahConcurrentGC::entry_weak_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent weak roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_weak_roots); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -554,7 +557,7 @@ void ShenandoahConcurrentGC::entry_class_unloading() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent class unloading", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_class_unload); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_class_unload); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -570,7 +573,7 @@ void ShenandoahConcurrentGC::entry_strong_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent strong roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_strong_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_strong_roots); EventMark em("%s", msg); ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_strong_roots); @@ -588,7 +591,7 @@ void ShenandoahConcurrentGC::entry_cleanup_early() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_early, true /* log_heap_usage */); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_early, false /* log_heap_usage */); EventMark em("%s", msg); // This phase does not use workers, no need for setup @@ -607,7 +610,7 @@ void ShenandoahConcurrentGC::entry_evacuate() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent evacuation", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_evac); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_evac); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -623,7 +626,7 @@ void ShenandoahConcurrentGC::entry_update_thread_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update thread roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_thread_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_update_thread_roots); EventMark em("%s", msg); // No workers used in this phase, no setup required @@ -636,7 +639,7 @@ void ShenandoahConcurrentGC::entry_update_refs() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent update references", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_update_refs); EventMark em("%s", msg); ShenandoahWorkerScope scope(heap->workers(), @@ -652,7 +655,7 @@ void ShenandoahConcurrentGC::entry_cleanup_complete() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent cleanup", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_complete, true /* log_heap_usage */); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_cleanup_complete, false /* log_heap_usage */); EventMark em("%s", msg); // This phase does not use workers, no need for setup @@ -664,7 +667,7 @@ void ShenandoahConcurrentGC::entry_reset_after_collect() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent reset after collect", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect); EventMark em("%s", msg); op_reset_after_collect(); @@ -1259,7 +1262,7 @@ void ShenandoahConcurrentGC::entry_final_roots() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent final roots", ""); - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_final_roots); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_final_roots); EventMark em("%s", msg); heap->concurrent_final_roots(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 7549fe023168..2c82271f07f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -282,7 +282,7 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau // ShenandoahHeap* heap = ShenandoahHeap::heap(); if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) { - log_info(gc)("Cancelled"); + log_info(gc, phases)("Cancelled"); return; } heap->increment_total_collections(false); @@ -371,7 +371,7 @@ void ShenandoahControlThread::notify_control_thread(GCCause::Cause cause) { void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { if (should_terminate()) { - log_info(gc)("Control thread is terminating, no more GCs"); + log_info(gc, phases)("Control thread is terminating, no more GCs"); return; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 439e23af2812..824f7bb432af 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -498,7 +498,7 @@ const char* ShenandoahDegenGC::degen_event_message(ShenandoahDegenPoint point) c } void ShenandoahDegenGC::upgrade_to_full() { - log_info(gc)("Degenerated GC upgrading to Full GC"); + log_info(gc, phases)("Degenerated GC upgrading to Full GC"); ShenandoahHeap* heap = ShenandoahHeap::heap(); heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc); heap->increment_total_collections(true); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 493736f4194e..139406246693 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -350,7 +350,7 @@ ShenandoahMarkingContext* ShenandoahGeneration::complete_marking_context() { } void ShenandoahGeneration::cancel_marking() { - log_info(gc)("Cancel marking: %s", name()); + log_info(gc, phases)("Cancel marking: %s", name()); if (is_concurrent_mark_in_progress()) { set_mark_incomplete(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 5d2e58559eee..c59f4992a7e2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -425,7 +425,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She if (_heap->cancelled_gc()) { // Young generation bootstrap cycle has failed. Concurrent mark for old generation // is going to resume after degenerated bootstrap cycle completes. - log_info(gc)("Bootstrap cycle for old generation was cancelled"); + log_info(gc, phases)("Bootstrap cycle for old generation was cancelled"); return; } @@ -656,7 +656,7 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera } // Cancel the old GC and wait for the control thread to start servicing the new request. - log_info(gc)("Preempting old generation mark to allow %s GC", generation->name()); + log_info(gc, phases)("Preempting old generation mark to allow %s GC", generation->name()); while (gc_mode() == servicing_old) { _heap->cancel_gc(GCCause::_shenandoah_concurrent_gc); notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc, generation); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 31129182380e..ef4ee13a7d41 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -1023,7 +1023,7 @@ void ShenandoahGenerationalHeap::complete_concurrent_cycle() { void ShenandoahGenerationalHeap::entry_global_coalesce_and_fill() { const char* msg = "Coalescing and filling old regions"; - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_coalesce_and_fill); + ShenandoahConcurrentSubphase gc_phase(msg, ShenandoahPhaseTimings::conc_coalesce_and_fill); TraceCollectorStats tcs(monitoring_support()->concurrent_collection_counters()); EventMark em("%s", msg); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp index c98b96c689b2..1ae080d31c64 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp @@ -86,6 +86,9 @@ bool ShenandoahOldGC::collect(GCCause::Cause cause) { assert(!_old_generation->is_preparing_for_mark(), "Old regions need to be parsable during concurrent mark."); heap->release_injected_pins(); + SHENANDOAH_EVENT_MESSAGE(msg, _generation->type(), "Concurrent GC", ""); + ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_gc, /* log_heap_usage = */ true); + // Enable preemption of old generation mark. _allow_preemption.set(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 0f01795bb4ce..958e7b3cf956 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -363,7 +363,7 @@ void ShenandoahOldGeneration::cancel_gc() { validate_idle(); #endif } else { - log_info(gc)("Terminating old gc cycle."); + log_info(gc, phases)("Terminating old gc cycle."); // Stop marking cancel_marking(); // Stop tracking old regions diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index dfb42e0b76f0..25ff982a9e4d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -51,6 +51,7 @@ class outputStream; SHENANDOAH_WORKER_PHASE_DO(NAME_PREFIX, DESC_PREFIX, f) #define SHENANDOAH_PHASE_DO(f) \ + SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_gc, "Concurrent GC") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_reset, "Concurrent Reset") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark_gross, "Pause Init Mark (G)") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark, "Pause Init Mark (N)") \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index c4204d852d58..fb6a77b48ae9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -100,6 +100,28 @@ ShenandoahGCPauseMark::ShenandoahGCPauseMark(uint gc_id, const char* notificatio ); } +ShenandoahPauseSubphase::ShenandoahPauseSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage) : + ShenandoahTimingsTracker(phase), + _tracer(title, nullptr, GCCause::_no_gc, log_heap_usage), + _timer(ShenandoahHeap::heap()->gc_timer()) { + _timer->register_gc_phase_start(title, Ticks::now()); +} + +ShenandoahPauseSubphase::~ShenandoahPauseSubphase() { + _timer->register_gc_phase_end(Ticks::now()); +} + +ShenandoahConcurrentSubphase::ShenandoahConcurrentSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage) : + ShenandoahTimingsTracker(phase), + _tracer(title, nullptr, GCCause::_no_gc, log_heap_usage), + _timer(ShenandoahHeap::heap()->gc_timer()) { + _timer->register_gc_phase_start(title, Ticks::now()); +} + +ShenandoahConcurrentSubphase::~ShenandoahConcurrentSubphase() { + _timer->register_gc_phase_end(Ticks::now()); +} + ShenandoahPausePhase::ShenandoahPausePhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage) : ShenandoahTimingsTracker(phase), _tracer(title, nullptr, GCCause::_no_gc, log_heap_usage), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 7b49854e16ca..e16801871c58 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -108,7 +108,35 @@ class ShenandoahTimingsTracker : public StackObj { }; /* - * ShenandoahPausePhase tracks a STW pause and emits Shenandoah timing and + * ShenandoahPauseSubphase tracks a STW pause and emits Shenandoah timing and + * a corresponding JFR event + */ +class ShenandoahPauseSubphase : public ShenandoahTimingsTracker { +private: + GCTraceTimeWrapper _tracer; + ConcurrentGCTimer* const _timer; + +public: + ShenandoahPauseSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false); + ~ShenandoahPauseSubphase(); +}; + +/* + * ShenandoahConcurrentSubphase tracks a concurrent GC phase and emits Shenandoah timing and + * a corresponding JFR event + */ +class ShenandoahConcurrentSubphase : public ShenandoahTimingsTracker { +private: + GCTraceTimeWrapper _tracer; + ConcurrentGCTimer* const _timer; + +public: + ShenandoahConcurrentSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false); + ~ShenandoahConcurrentSubphase(); +}; + +/* + * ShenandoahPausePhase tracks a pause GC phase and emits Shenandoah timing and * a corresponding JFR event */ class ShenandoahPausePhase : public ShenandoahTimingsTracker { From 1530af5566db05941ab77bce81f423c9587e4981 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 20 Aug 2026 17:48:53 +0000 Subject: [PATCH 010/223] 8390613: Missing class in loadable descriptors causes AOT crash Reviewed-by: dholmes, kvn --- src/hotspot/share/oops/instanceKlass.cpp | 19 ++++- .../aotCache/LoadableDescriptorTest.java | 79 +++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/LoadableDescriptorTest.java diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 010510c2f3fd..65068c25d80a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1075,11 +1075,24 @@ static void load_classes_from_loadable_descriptors_attribute(InstanceKlass *ik, TempNewSymbol class_name = Signature::strip_envelope(sig); if (class_name == ik->name()) continue; log_info(class, preload)("Preloading of class %s during linking of class %s " - "because of the class is listed in the LoadableDescriptors attribute", + "because the class is listed in the LoadableDescriptors attribute", sig->as_C_string(), ik->name()->as_C_string()); oop loader = ik->class_loader(); - Klass* klass = SystemDictionary::resolve_or_null(class_name, - Handle(THREAD, loader), THREAD); + Klass* klass = nullptr; + + if (CDSConfig::is_using_aot_linked_classes() && ik->in_aot_cache() && !ik->defined_by_other_loaders()) { + // + We come to here during AOTLinkedClassBulkLoader::link_classes() and it's too early to + // execute any Java code. + // + All loadable descriptors that can be resolved would have been resolved during the AOT assembly + // phase, and would have been loaded earlier by AOTLinkedClassBulkLoader, so they can be found in + // the system dictionary. + // + If no class of the given name have been loaded yet, it's most likely because the class + // is missing from JAR files. Just ignore it. + klass = SystemDictionary::find_instance_or_array_klass(THREAD, class_name, Handle(THREAD, loader)); + } else { + klass = SystemDictionary::resolve_or_null(class_name, + Handle(THREAD, loader), THREAD); + } if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/LoadableDescriptorTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/LoadableDescriptorTest.java new file mode 100644 index 000000000000..da85f306bd4e --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/LoadableDescriptorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Handling of missing classes referred to by loadable descriptors. + * @bug 8390613 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib + * @enablePreview + * @build LoadableDescriptorTest + * @comment Omit the Line class when creating app.jar + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar LoadableDescriptorApp Point + * @run driver LoadableDescriptorTest -XX:+AOTClassLinking + * @run driver LoadableDescriptorTest -XX:-AOTClassLinking + */ + +import jdk.test.lib.cds.SimpleCDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class LoadableDescriptorTest { + public static void main(String[] args) throws Exception { + final String mainClass = LoadableDescriptorApp.class.getName(); + final String appJar = ClassFileInstaller.getJarPath("app.jar"); + + SimpleCDSAppTester tester = SimpleCDSAppTester.of("LoadableDescriptorTest"); + tester.addVmArgs("-Xlog:aot+class=debug,class+preload", "--enable-preview", args[0]) + .appCommandLine(mainClass) + .classpath(appJar) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("LoadableDescriptorApp: success") + .shouldContain("Preloading of class Point during linking of class LoadableDescriptorApp (cause: LoadableDescriptors attribute) succeeded") + .shouldContain("Preloading of class Line during linking of class LoadableDescriptorApp (cause: LoadableDescriptors attribute) failed"); + }); + tester.runAOTWorkflow(); + } +} + +class LoadableDescriptorApp { + public static void main(String[] args) { + LoadableDescriptorApp app = new LoadableDescriptorApp(); + app.foo(null, null); + app.bar(null, null); + System.out.println("LoadableDescriptorApp: success"); + } + + // "Point" and "Line" are (symbolically) declared in the loadable descriptors of the + // LoadableDescriptorApp class. However, Line is not in app.jar so it cannot be resolved + // when LoadableDescriptorApp is linked. + + void foo(Point p1, Point p2) {} + void bar(Line a, Line b) {} +} + +value record Point(byte x, byte y) { } +value record Line(Point a, Point b) { } + From 09868aaf95a1ea0dc7af623effc04246c7ed1c94 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 20 Aug 2026 19:42:41 +0000 Subject: [PATCH 011/223] 8390481: stop002 test should no longer call Thread.interrupted() to work around JDK-8306324 Reviewed-by: dholmes, kevinw --- .../vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java index 02d49f76de70..0d87338f6781 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,8 +119,6 @@ private int runIt(String args[]) { return Consts.TEST_FAILED; } } catch (Throwable t) { - // Call Thread.interrupted(). Workaround for JDK-8306324 - log.display("TEST #3: interrupted = " + Thread.interrupted()); // We don't expect the exception to be thrown when in vthread mode. if (!vthreadMode && t instanceof MyThrowable) { log.display("TEST #3: Caught expected exception while in loop: " + t); From e296cefb588675b3b32b58fdc283108f7d1cec06 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Thu, 20 Aug 2026 19:52:10 +0000 Subject: [PATCH 012/223] 8390485: Migrate appcds/aotCache/ tests to AOT workflow Reviewed-by: iklam, kvn --- test/hotspot/jtreg/ProblemList.txt | 6 - .../appcds/aotCache/SharedSecretsTest.java | 2 +- .../AOTClassLinkingVMOptions.java | 179 ++++++++++++------ .../aotCache/aotClassLinking/AddExports.java | 3 +- .../aotCache/aotClassLinking/AddOpens.java | 3 +- .../aotCache/aotClassLinking/AddReads.java | 3 +- .../aotCode/AOTCodeCompressedOopsTest.java | 6 +- .../resolvedConstants/AOTLinkedLambdas.java | 57 +++--- .../AOTLinkedVarHandles.java | 48 +++-- test/lib/jdk/test/lib/cds/CDSAppTester.java | 2 +- .../jdk/test/lib/cds/SimpleCDSAppTester.java | 19 +- 11 files changed, 195 insertions(+), 133 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 3e73792dd7df..4ab802a270b8 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -97,12 +97,6 @@ gc/TestGCALotAtAllSafepoints.java#Shenandoah 8390661 generic-all # :hotspot_runtime -runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java 8390485 generic-all -runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java 8390485 generic-all -runtime/cds/appcds/aotCache/aotClassLinking/AddOpens.java 8390485 generic-all -runtime/cds/appcds/aotCache/aotClassLinking/AddReads.java 8390485 generic-all -runtime/cds/appcds/resolvedConstants/AOTLinkedLambdas.java 8390485 generic-all -runtime/cds/appcds/resolvedConstants/AOTLinkedVarHandles.java 8390485 generic-all runtime/jni/terminatedThread/TestTerminatedThread.java 8317789 aix-ppc64 runtime/Monitor/SyncOnValueBasedClassTest.java 8340995 linux-s390x runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/SharedSecretsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/SharedSecretsTest.java index 5d6e909b7515..91077591793d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/SharedSecretsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/SharedSecretsTest.java @@ -46,7 +46,7 @@ public class SharedSecretsTest { public static void main(String[] args) throws Exception { Tester t = new Tester(mainClass); t.setCheckExitValue(false); - t.runAOTAssemblyWorkflow(); + t.runAOTTrainingAndAssemblyWorkflow(); } static class Tester extends CDSAppTester { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java index bee0fa60f49e..2214d5e4e5e4 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AOTClassLinkingVMOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,14 +40,15 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.cds.CDSModulePackager; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; public class AOTClassLinkingVMOptions { static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "Hello"; static int testCaseNum = 0; static void testCase(String s) { @@ -56,53 +57,95 @@ static void testCase(String s) { } public static void main(String[] args) throws Exception { - TestCommon.testDump(appJar, TestCommon.list("Hello"), - "-XX:+AOTClassLinking"); + SimpleCDSAppTester t = SimpleCDSAppTester.of("AOTClassLinking") + .classpath(appJar) + .addVmArgs("-XX:+AOTClassLinking") + .appCommandLine(mainClass) + .runAOTTrainingAndAssemblyWorkflow(); testCase("Archived full module graph must be enabled at runtime"); - TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello") - .assertAbnormalExit("shared archive file has aot-linked classes." + + t.setVmArgs("-Djdk.module.validation=1") + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + " It cannot be used when archived full module graph is not used"); + }) + .productionRun(); testCase("Cannot use -Djava.system.class.loader"); - TestCommon.run("-cp", appJar, "-Djava.system.class.loader=dummy", "Hello") - .assertAbnormalExit("shared archive file has aot-linked classes." + - " It cannot be used when the java.system.class.loader property is specified."); + t.setVmArgs("-Djava.system.class.loader=dummy") + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + + " It cannot be used when the java.system.class.loader property is specified."); + }) + .productionRun(); testCase("Cannot use a different main module"); - TestCommon.run("-cp", appJar, "-Xlog:cds", "-m", "jdk.compiler/com.sun.tools.javac.Main") - .assertAbnormalExit("shared archive file has aot-linked classes." + + t.setVmArgs() + .appCommandLine("-m", "jdk.compiler/com.sun.tools.javac.Main") + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + " It cannot be used when archived full module graph is not used."); + }) + .productionRun(); + testCase("Cannot use security manager"); - TestCommon.run("-cp", appJar, "-Xlog:cds", "-Djava.security.manager=allow") - .assertAbnormalExit("shared archive file has aot-linked classes." + + t.setVmArgs("-Djava.security.manager=allow") + .appCommandLine(mainClass) + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + " It cannot be used with -Djava.security.manager=allow."); - TestCommon.run("-cp", appJar, "-Xlog:cds", "-Djava.security.manager=default") - .assertAbnormalExit("shared archive file has aot-linked classes." + + }) + .productionRun(); + + t.setVmArgs("-Djava.security.manager=default") + .appCommandLine(mainClass) + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + " It cannot be used with -Djava.security.manager=default."); + }) + .productionRun(); // Dumping with AOTInvokeDynamicLinking disabled - TestCommon.testDump(appJar, TestCommon.list("Hello"), - "-XX:+UnlockDiagnosticVMOptions", "-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking"); + t.setVmArgs("-XX:+UnlockDiagnosticVMOptions", "-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking") + .appCommandLine(mainClass) + .setCheckExitValue(true) + .runAOTTrainingAndAssemblyWorkflow(); testCase("Use the archive that was created with -XX:-AOTInvokeDynamicLinking."); - TestCommon.run("-cp", appJar, "Hello") - .assertNormalExit("Hello"); + t.setVmArgs() + .appCommandLine(mainClass) + .setCheckExitValue(true) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(0); + out.shouldMatch("Hello"); + }) + .productionRun(); testCase("Archived full module graph must be enabled at runtime (with -XX:-AOTInvokeDynamicLinking)"); - TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello") - .assertAbnormalExit("shared archive file has aot-linked classes." + + t.setVmArgs("-Djdk.module.validation=1") + .appCommandLine(mainClass) + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldMatch("AOT cache has aot-linked classes." + " It cannot be used when archived full module graph is not used"); + }) + .productionRun(); // NOTE: tests for ClassFileLoadHook + AOTClassLinking is in // ../jvmti/ClassFileLoadHookTest.java - boolean dynamicMode = Boolean.getBoolean("test.dynamic.cds.archive"); - if (!dynamicMode) { - // These tests need to dump the full module graph, which is not possible with - // dynamic dump. - modulePathTests(); - } + modulePathTests(); } static void modulePathTests() throws Exception { @@ -112,47 +155,61 @@ static void modulePathTests() throws Exception { String MAIN_MODULE = "com.foos"; String MAIN_CLASS = "com.foos.Test"; - String[] appClasses = {MAIN_CLASS}; - CDSModulePackager modulePackager = new CDSModulePackager(SRC_DIR); modulePackager.createModularJarWithMainClass(MAIN_MODULE, MAIN_CLASS); String modulePath = modulePackager.getOutputDir().toString(); testCase("Cannot use mis-matched module path"); - TestCommon.testDump(null, appClasses, - "--module-path", modulePath, - "-XX:+AOTClassLinking", - "-m", MAIN_MODULE); - TestCommon.run("-Xlog:aot", - "-Xlog:cds", - "--module-path", modulePath, - "-m", MAIN_MODULE) - .assertNormalExit("Using AOT-linked classes: true"); - - TestCommon.run("-Xlog:aot", - "-Xlog:cds", - "--module-path", modulePath + "/bad", - "-m", MAIN_MODULE) - .assertAbnormalExit("shared archive file has aot-linked classes. It cannot be used when archived full module graph is not used."); + SimpleCDSAppTester t = SimpleCDSAppTester.of("ModuleTests") + .modulepath(modulePath) + .addVmArgs("-XX:+AOTClassLinking") + .appCommandLine("-m", MAIN_MODULE) + .runAOTTrainingAndAssemblyWorkflow(); + + t.setVmArgs("-Xlog:aot", "-Xlog:cds") + .modulepath(modulePath) + .appCommandLine("-m", MAIN_MODULE) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Using AOT-linked classes: true"); + }) + .productionRun(); + + t.setVmArgs("-Xlog:aot=debug", "-Xlog:cds") + .modulepath(modulePath + "/bad") + .appCommandLine( "-m", MAIN_MODULE) + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldContain("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)"); + }) + .productionRun(); testCase("Cannot use mis-matched --add-modules"); - TestCommon.testDump(null, appClasses, - "--module-path", modulePath, - "-XX:+AOTClassLinking", - "--add-modules", MAIN_MODULE); - TestCommon.run("-Xlog:aot", - "-Xlog:cds", - "--module-path", modulePath, - "--add-modules", MAIN_MODULE, - MAIN_CLASS) - .assertNormalExit("Using AOT-linked classes: true"); - - TestCommon.run("-Xlog:cds", - "--module-path", modulePath, - "--add-modules", "java.base", - MAIN_CLASS) - .assertAbnormalExit("Mismatched values for property jdk.module.addmods", - "shared archive file has aot-linked classes. It cannot be used when archived full module graph is not used."); + t.setVmArgs("-XX:+AOTClassLinking", "--add-modules", MAIN_MODULE) + .modulepath(modulePath) + .appCommandLine(MAIN_CLASS) + .setCheckExitValue(true) + .runAOTTrainingAndAssemblyWorkflow(); + + t.setVmArgs("-Xlog:aot", "-Xlog:cds", "--add-modules", MAIN_MODULE) + .modulepath(modulePath) + .appCommandLine(MAIN_CLASS) + .setCheckExitValue(true) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Using AOT-linked classes: true"); + }) + .productionRun(); + + t.setVmArgs("-Xlog:cds", "--add-modules", "java.base") + .modulepath(modulePath) + .appCommandLine(MAIN_CLASS) + .setCheckExitValue(false) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldContain("Mismatched values for property jdk.module.addmods"); + out.shouldContain("AOT cache has aot-linked classes. It cannot be used when archived full module graph is not used."); + }) + .productionRun(); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java index fc3e945cf9d9..fc9766685f27 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddExports.java @@ -44,8 +44,9 @@ public class AddExports { static final String SEP = File.separator; + // runtime/cds/appcds/jigsaw/modulepath/src static final Path SRC = Paths.get(System.getProperty("test.src")). - resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); + resolve( ".." + SEP + ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); static final Path nonModuleNeedsJdkAddExportDir = SRC.resolve("com.nomodule.needsjdkaddexport"); static final String nonModuleNeedsJdkAddExportJar = "nonModuleNeedsJdkAddExport.jar"; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddOpens.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddOpens.java index 694e653676e4..6f209370710c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddOpens.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddOpens.java @@ -46,8 +46,9 @@ public class AddOpens { private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + // runtime/cds/appcds/jigsaw/modulepath/src private static final Path SRC_DIR = Paths.get(System.getProperty("test.src")). - resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); + resolve( ".." + SEP + ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); private static final Path MODS_DIR = Paths.get("mods"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddReads.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddReads.java index 347e61fed4ca..558f0149fe47 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddReads.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/AddReads.java @@ -48,8 +48,9 @@ public class AddReads { private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + // runtime/cds/appcds/jigsaw/modulepath/src private static final Path SRC_DIR = Paths.get(System.getProperty("test.src")). - resolve( ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); + resolve( ".." + SEP + ".." + SEP + "jigsaw" + SEP + "modulepath" + SEP + "src"); private static final Path MODS_DIR = Paths.get("mods"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 29b0f59b2380..b0d65fe48be1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -51,7 +51,7 @@ public static void main(String... args) throws Exception { { Tester t = new Tester(); t.setHeapConfig(Tester.RunMode.ASSEMBLY, true, true); - t.runAOTAssemblyWorkflow(); + t.runAOTTrainingAndAssemblyWorkflow(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, true); t.productionRun(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, false); @@ -62,7 +62,7 @@ public static void main(String... args) throws Exception { { Tester t = new Tester(); t.setHeapConfig(Tester.RunMode.ASSEMBLY, true, false); - t.runAOTAssemblyWorkflow(); + t.runAOTTrainingAndAssemblyWorkflow(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, true); t.productionRun(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, false); @@ -73,7 +73,7 @@ public static void main(String... args) throws Exception { { Tester t = new Tester(); t.setHeapConfig(Tester.RunMode.ASSEMBLY, false, false); - t.runAOTAssemblyWorkflow(); + t.runAOTTrainingAndAssemblyWorkflow(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, true); t.productionRun(); t.setHeapConfig(Tester.RunMode.PRODUCTION, true, false); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedLambdas.java b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedLambdas.java index ecfaa2659234..08c9191a33c8 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedLambdas.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedLambdas.java @@ -43,48 +43,43 @@ import static java.util.stream.Collectors.*; import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; public class AOTLinkedLambdas { - static final String classList = "AOTLinkedLambdas.classlist"; static final String appJar = ClassFileInstaller.getJarPath("app.jar"); static final String mainClass = AOTLinkedLambdasApp.class.getName(); public static void main(String[] args) throws Exception { - CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass) - .assertNormalExit(output -> { - output.shouldContain("Hello AOTLinkedLambdasApp"); - }); - - CDSOptions opts = (new CDSOptions()) - .addPrefix("-XX:ExtraSharedClassListFile=" + classList, + SimpleCDSAppTester t = SimpleCDSAppTester.of("AOTLinkedLambdas") + .classpath(appJar) + .addVmArgs("-esa", // see JDK-8340836 "-XX:+AOTClassLinking", "-Xlog:aot+resolve=trace", "-Xlog:aot+class=debug", - "-Xlog:cds+class=debug", - "-cp", appJar); - - OutputAnalyzer dumpOut = CDSTestUtils.createArchiveAndCheck(opts); - dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type IA"); - dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type IB"); - dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IC"); - dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type ID2"); - dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IE2"); // unsupported = IE1 - dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IF2"); - dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IG2"); - dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IH3"); // unsupported = IH1 - - CDSOptions runOpts = (new CDSOptions()) - .setUseVersion(false) - .addPrefix("-Xlog:cds", - "-esa", // see JDK-8340836 - "-cp", appJar) - .addSuffix(mainClass); - - CDSTestUtils.run(runOpts) - .assertNormalExit("Hello AOTLinkedLambdasApp", - "hello, world"); + "-Xlog:cds+class=debug") + .appCommandLine(mainClass) + .setTrainingChecker((OutputAnalyzer output) -> { + output.shouldContain("Hello AOTLinkedLambdasApp"); + }) + .setAssemblyChecker((OutputAnalyzer dumpOut) -> { + dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type IA"); + dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type IB"); + dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IC"); + dumpOut.shouldContain("Can aot-resolve Lambda proxy of interface type ID2"); + dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IE2"); // unsupported = IE1 + dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IF2"); + dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IG2"); + dumpOut.shouldContain("Cannot aot-resolve Lambda proxy of interface type IH3"); // unsupported = IH1 + }) + .runAOTTrainingAndAssemblyWorkflow(); + + t.setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Hello AOTLinkedLambdasApp"); + out.shouldContain("hello, world"); + }) + .productionRun(); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedVarHandles.java b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedVarHandles.java index 1089e849a905..78e881a99753 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedVarHandles.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/AOTLinkedVarHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,42 +39,38 @@ import java.lang.invoke.VarHandle; import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; public class AOTLinkedVarHandles { - static final String classList = "AOTLinkedVarHandles.classlist"; static final String appJar = ClassFileInstaller.getJarPath("app.jar"); static final String mainClass = AOTLinkedVarHandlesApp.class.getName(); public static void main(String[] args) throws Exception { - CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass) - .assertNormalExit(output -> { - output.shouldContain("Hello AOTLinkedVarHandlesApp"); - }); - - CDSOptions opts = (new CDSOptions()) - .addPrefix("-XX:ExtraSharedClassListFile=" + classList, + SimpleCDSAppTester t = SimpleCDSAppTester.of("AOTLinkedVarHandles") + .classpath(appJar) + .appCommandLine(mainClass) + .addVmArgs("-esa", "-XX:+AOTClassLinking", "-Xlog:aot+resolve=trace", - "-Xlog:cds+class=debug", - "-cp", appJar); - - String s = "archived method CP entry.* AOTLinkedVarHandlesApp "; - OutputAnalyzer dumpOut = CDSTestUtils.createArchiveAndCheck(opts); - dumpOut.shouldMatch(s + "java/lang/invoke/VarHandle.compareAndExchangeAcquire:\\(\\[DIDI\\)D =>"); - dumpOut.shouldMatch(s + "java/lang/invoke/VarHandle.get:\\(\\[DI\\)D => "); - dumpOut.shouldNotContain("rejected .* CP entry.*"); - - CDSOptions runOpts = (new CDSOptions()) - .setUseVersion(false) - .addPrefix("-Xlog:cds", - "-esa", - "-cp", appJar) - .addSuffix(mainClass); + "-Xlog:cds+class=debug") + .setTrainingChecker((OutputAnalyzer output) -> { + output.shouldContain("Hello AOTLinkedVarHandlesApp"); + }) + .setAssemblyChecker((OutputAnalyzer output) -> { + String s = "archived method CP entry.* AOTLinkedVarHandlesApp "; + output.shouldMatch(s + "java/lang/invoke/VarHandle.compareAndExchangeAcquire:\\(\\[DIDI\\)D =>"); + output.shouldMatch(s + "java/lang/invoke/VarHandle.get:\\(\\[DI\\)D => "); + output.shouldNotContain("rejected .* CP entry.*"); + }) + .runAOTTrainingAndAssemblyWorkflow(); - CDSTestUtils.run(runOpts) - .assertNormalExit("Hello AOTLinkedVarHandlesApp"); + t.setVmArgs("-Xlog:cds,aot", "-esa") + .setProductionChecker((OutputAnalyzer output) -> { + output.shouldContain("Hello AOTLinkedVarHandlesApp"); + }) + .productionRun(); } } diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index 0be21b9ec274..07b2981d4d39 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -542,7 +542,7 @@ public void runAOTWorkflow(String... args) throws Exception { } // See JEP 483; stop at the assembly run; do not execute production run - public void runAOTAssemblyWorkflow() throws Exception { + public void runAOTTrainingAndAssemblyWorkflow() throws Exception { this.workflow = Workflow.AOT; recordAOTConfiguration(); createAOTCache(); diff --git a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java index 73e45711fe91..ab8f85961b65 100644 --- a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java @@ -98,6 +98,12 @@ public SimpleCDSAppTester addVmArgs(String... args) { return this; } + // Replace VM args with new list + public SimpleCDSAppTester setVmArgs(String... args) { + vmArgs = args; + return this; + } + public SimpleCDSAppTester appCommandLine(String... args) { this.appCommandLine = args; return this; @@ -207,6 +213,16 @@ public SimpleCDSAppTester runAOTWorkflow() throws Exception { return this; } + public SimpleCDSAppTester runAOTTrainingAndAssemblyWorkflow() throws Exception { + tester.runAOTTrainingAndAssemblyWorkflow(); + return this; + } + + public SimpleCDSAppTester productionRun() throws Exception { + tester.productionRun(); + return this; + } + public SimpleCDSAppTester run(String args[]) throws Exception { tester.run(args); return this; @@ -226,7 +242,8 @@ public String aotCacheFile() { return tester.aotCacheFile(); } - public void setCheckExitValue(boolean b) { + public SimpleCDSAppTester setCheckExitValue(boolean b) { tester.setCheckExitValue(b); + return this; } } From 3245eb2fe98b1f00897437d2f7f8fdaf44b6158e Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 20 Aug 2026 22:55:42 +0000 Subject: [PATCH 013/223] 8390310: Shenandoah: Abbreviated cycles should allow promotion-in-place Reviewed-by: shade, kdnilsen --- .../shenandoahGenerationalHeuristics.cpp | 158 +++++++----- .../shenandoahGenerationalHeuristics.hpp | 25 +- .../heuristics/shenandoahHeuristics.cpp | 12 +- .../heuristics/shenandoahHeuristics.hpp | 6 +- .../gc/shenandoah/shenandoahAgeCensus.hpp | 7 + .../gc/shenandoah/shenandoahHeapRegion.hpp | 1 + .../shenandoah/shenandoahInPlacePromoter.cpp | 53 ++--- .../shenandoah/shenandoahInPlacePromoter.hpp | 10 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 1 - .../gc/shenandoah/shenandoahOldGeneration.hpp | 9 - .../share/gc/shenandoah/shenandoahTrace.cpp | 18 +- .../share/gc/shenandoah/shenandoahTrace.hpp | 5 +- ...tPromoteInPlaceDuringAbbreviatedCycle.java | 225 ++++++++++++++++++ 13 files changed, 394 insertions(+), 136 deletions(-) create mode 100644 test/hotspot/jtreg/gc/shenandoah/generational/TestPromoteInPlaceDuringAbbreviatedCycle.java diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index ca4dfc71c61a..dbc795651f22 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -38,8 +38,6 @@ #include "logging/log.hpp" #include "utilities/quickSort.hpp" -using idx_t = ShenandoahSimpleBitMap::idx_t; - static int compare_by_aged_live(AgedRegionData a, AgedRegionData b) { if (a._live_data < b._live_data) return -1; @@ -77,6 +75,73 @@ ShenandoahGenerationalHeuristics::ShenandoahGenerationalHeuristics(ShenandoahGen : ShenandoahAdaptiveHeuristics(generation), _generation(generation), _add_regions_to_old(0) { } +void ShenandoahGenerationalHeuristics::prepare_for_abbreviated_cycle() { + auto const heap = ShenandoahGenerationalHeap::heap(); + adjust_reserves_for_abbreviated(heap); + + ShenandoahInPlacePromotionPlanner in_place_promotions(heap); + ShenandoahAgeCensus* census = heap->age_census(); + if (census->get_tenurable_bytes(census->effective_threshold()) != 0) { + prepare_regions_for_promotion(in_place_promotions, heap, nullptr); + } + in_place_promotions.complete_planning(); + + // Only these in-place promotion regions will be tenured this cycle + const size_t tenurable_this_cycle = in_place_promotions.live_bytes(); + compute_promotion_potential(heap, tenurable_this_cycle); + + ShenandoahTracer::report_promotion_info(heap->collection_set(), in_place_promotions); +} + +void ShenandoahGenerationalHeuristics::adjust_reserves_for_abbreviated(ShenandoahGenerationalHeap* heap) { + // We are not going to evacuate because this is an abbreviated cycle. Reset the reserves. + heap->young_generation()->set_evacuation_reserve(0UL); + heap->old_generation()->set_evacuation_reserve(0UL); + heap->old_generation()->set_promoted_reserve(0UL); +} + +size_t ShenandoahGenerationalHeuristics::prepare_regions_for_promotion(ShenandoahInPlacePromotionPlanner& in_place_promotions, + ShenandoahGenerationalHeap* heap, + AgedRegionData* sorted_regions) { + // There should be no regions configured for subsequent in-place-promotions carried over from the previous cycle. + assert_no_in_place_promotions(); + size_t candidates = 0; + for (size_t i = 0, num_regions = heap->num_regions(); i < num_regions; i++) { + ShenandoahHeapRegion* const r = heap->get_region(i); + if (r->is_empty() || !r->has_live() || !r->is_young()) { + // skip over regions that aren't young with some live data + continue; + } + + if (!r->is_regular()) { + if (r->is_humongous_start() && heap->is_tenurable(r)) { + in_place_promotions.prepare(r); + } + // Nothing else to be done for humongous regions + continue; + } + + if (heap->is_tenurable(r)) { + if (in_place_promotions.is_eligible(r)) { + // We prefer to promote this region in place because it has a small amount of garbage and a large usage. + // Note that if this region has been used recently for allocation, it will not be promoted, and it will + // not be selected for promotion by evacuation. + in_place_promotions.prepare(r); + } else if (sorted_regions != nullptr) { + // Record this promotion-eligible candidate region. After sorting and selecting the best candidates below, + // we may still decide to exclude this promotion-eligible region from the current collection set. If this + // happens, we will consider this region as part of the anticipated promotion potential for the next GC + // pass; see further below. + sorted_regions[candidates]._region = r; + sorted_regions[candidates]._live_data = r->get_live_data_bytes(); + candidates++; + } + } + } + + return candidates; +} + void ShenandoahGenerationalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* collection_set, RegionData* data, size_t data_size, size_t free) { @@ -99,13 +164,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set_from_regiondata(She heap->shenandoah_policy()->record_mixed_cycle(); } - ShenandoahTracer::report_promotion_info(collection_set, - in_place_promotions.humongous_region_stats().count, - in_place_promotions.humongous_region_stats().garbage, - in_place_promotions.humongous_region_stats().free, - in_place_promotions.regular_region_stats().count, - in_place_promotions.regular_region_stats().garbage, - in_place_promotions.regular_region_stats().free); + ShenandoahTracer::report_promotion_info(collection_set, in_place_promotions); } void ShenandoahGenerationalHeuristics::compute_evacuation_budgets(ShenandoahInPlacePromotionPlanner& in_place_promotions, @@ -285,75 +344,46 @@ void ShenandoahGenerationalHeuristics::add_tenured_regions_to_collection_set(con // reserved in the young generation. size_t ShenandoahGenerationalHeuristics::select_aged_regions(ShenandoahInPlacePromotionPlanner& in_place_promotions, const size_t old_promotion_reserve) { - - // There should be no regions configured for subsequent in-place-promotions carried over from the previous cycle. - assert_no_in_place_promotions(); - auto const heap = ShenandoahGenerationalHeap::heap(); - size_t candidates = 0; - // Sort the promotion-eligible regions in order of increasing live-data-bytes so that we can first reclaim regions that require // less evacuation effort. This prioritizes garbage first, expanding the allocation pool early before we reclaim regions that - // have more live data. - const idx_t num_regions = heap->num_regions(); - + // have more live data. This also prepares regions for in-place promotions ResourceMark rm; - AgedRegionData* sorted_regions = NEW_RESOURCE_ARRAY(AgedRegionData, num_regions); - - for (idx_t i = 0; i < num_regions; i++) { - ShenandoahHeapRegion* const r = heap->get_region(i); - if (r->is_empty() || !r->has_live() || !r->is_young()) { - // skip over regions that aren't young with some live data - continue; - } - - if (!r->is_regular()) { - if (r->is_humongous_start() && heap->is_tenurable(r)) { - in_place_promotions.prepare(r); - } - // Nothing else to be done for humongous regions - continue; - } - - if (heap->is_tenurable(r)) { - if (in_place_promotions.is_eligible(r)) { - // We prefer to promote this region in place because it has a small amount of garbage and a large usage. - // Note that if this region has been used recently for allocation, it will not be promoted and it will - // not be selected for promotion by evacuation. - in_place_promotions.prepare(r); - } else { - // Record this promotion-eligible candidate region. After sorting and selecting the best candidates below, - // we may still decide to exclude this promotion-eligible region from the current collection set. If this - // happens, we will consider this region as part of the anticipated promotion potential for the next GC - // pass; see further below. - sorted_regions[candidates]._region = r; - sorted_regions[candidates]._live_data = r->get_live_data_bytes(); - candidates++; - } - } - } - + AgedRegionData* sorted_regions = NEW_RESOURCE_ARRAY(AgedRegionData, heap->num_regions()); + const size_t candidates = prepare_regions_for_promotion(in_place_promotions, heap, sorted_regions); in_place_promotions.complete_planning(); add_tenured_regions_to_collection_set(old_promotion_reserve, heap, candidates, sorted_regions); - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); - const size_t tenurable_this_cycle = heap->age_census()->get_tenurable_bytes(tenuring_threshold); - const size_t tenurable_next_cycle = heap->age_census()->get_tenurable_bytes(tenuring_threshold - 1); - assert(tenurable_next_cycle >= tenurable_this_cycle, - "Tenurable next cycle (" PROPERFMT ") should include tenurable this cycle (" PROPERFMT ")", - PROPERFMTARGS(tenurable_next_cycle), PROPERFMTARGS(tenurable_this_cycle)); - - const size_t max_promotions = tenurable_this_cycle * ShenandoahPromoEvacWaste; + // Act as though everything that can be tenured, will be tenured. This overestimates how much will be promoted, + // but has the effect of tending to keep the old generation smaller because it believes less will be tenured + // on the next cycle. + const size_t tenurable_this_cycle = heap->age_census()->get_tenurable_bytes(); + const size_t max_promotions = compute_promotion_potential(heap, tenurable_this_cycle); const size_t old_consumed = MIN2(max_promotions, old_promotion_reserve); + return old_consumed; +} + +size_t ShenandoahGenerationalHeuristics::compute_promotion_potential(ShenandoahGenerationalHeap* const heap, + size_t tenurable_this_cycle) { + const uint effective_threshold = heap->age_census()->effective_threshold(); + const uint next_threshold = effective_threshold > 0 ? effective_threshold - 1 : 0; + const size_t tenurable_next_cycle = heap->age_census()->get_tenurable_bytes(next_threshold); + + // This assertion still holds even when tenurable_this_cycle is derived from in-place-promotions + // alone. The census cohort index is the region age plus the object's age, so every byte in a pip + // region is counted in the census. + assert(tenurable_next_cycle >= tenurable_this_cycle, + "Tenurable next cycle (" PROPERFMT ") should include tenurable this cycle (" PROPERFMT ")", + PROPERFMTARGS(tenurable_next_cycle), PROPERFMTARGS(tenurable_this_cycle)); // Don't include the bytes we expect to promote in this cycle in the next cycle - const size_t promo_potential = (tenurable_next_cycle - tenurable_this_cycle) * ShenandoahPromoEvacWaste; + const size_t remaining = tenurable_next_cycle > tenurable_this_cycle ? tenurable_next_cycle - tenurable_this_cycle : 0; + const size_t promo_potential = remaining * ShenandoahPromoEvacWaste; heap->old_generation()->set_promotion_potential(promo_potential); log_info(gc, ergo)("Promotion potential of aged regions with sufficient garbage: " PROPERFMT, PROPERFMTARGS(promo_potential)); - - return old_consumed; + return tenurable_this_cycle * ShenandoahPromoEvacWaste; } // Having chosen the collection set, adjust the budgets for generational mode based on its composition. Note diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index 1860e3d4c0f2..574e65aa6c0f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -33,6 +33,7 @@ class ShenandoahGeneration; class ShenandoahHeap; class ShenandoahCollectionSet; class RegionData; +class ShenandoahGenerationalHeap; typedef struct { ShenandoahHeapRegion* _region; @@ -58,12 +59,24 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { void record_cycle_end() override; protected: + // Select regions for in place promotion and zero evacuation reserves + void prepare_for_abbreviated_cycle() override; + // Wraps budget computation, subclass region selection, budget adjustment, and tracing. void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, RegionData* data, size_t data_size, size_t free) override; private: + // When we decide to do an abbreviated cycle, withdraw reserves so memory can be made available to mutators. + void adjust_reserves_for_abbreviated(ShenandoahGenerationalHeap* heap); + + // Select regions for in place promotion and optionally record tenurable regions that are not eligible + // for in-place promotion in the given sorted_regions array for possible inclusion in the collection set. + size_t prepare_regions_for_promotion(ShenandoahInPlacePromotionPlanner& in_place_promotions, + ShenandoahGenerationalHeap* heap, + AgedRegionData* sorted_regions); + // Compute evacuation budgets prior to choosing collection set. void compute_evacuation_budgets(ShenandoahInPlacePromotionPlanner& in_place_promotions, ShenandoahHeap* const heap); @@ -77,11 +90,10 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { // being those of at least tenuring_threshold age that have lower garbage // density. // - // Updates promotion_potential and pad_for_promote_in_place fields - // of the heap. Returns bytes of live object memory in the preselected - // regions, which are marked in the preselected_regions() indicator - // array of the heap's collection set, which should be initialized - // to false. + // Updates promotion_potential field of the heap. Returns bytes of live object + // memory in the preselected regions, which are marked in the + // preselected_regions() indicator array of the heap's collection set, which + // should be initialized to false. size_t select_aged_regions(ShenandoahInPlacePromotionPlanner& in_place_promotions, const size_t old_promotion_reserve); // Select regions for inclusion in the collection set that are tenured, but do @@ -90,6 +102,9 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { ShenandoahGenerationalHeap *const heap, size_t candidates, AgedRegionData* sorted_regions); + // Updates the anticipated promotions for the next cycle and returns the maximum promotions for the current cycle + size_t compute_promotion_potential(ShenandoahGenerationalHeap* heap, size_t tenurable_this_cycle); + // Adjust evacuation budgets after choosing collection set. On entry, the instance variable _regions_to_xfer // represents regions to be transferred to old based on decisions made in top_off_collection_set() void adjust_evacuation_budgets(ShenandoahGenerationalHeap* const heap, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 74b62003f86c..a0aec3c70a29 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -152,9 +152,10 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec if (immediate_percent <= ShenandoahImmediateThreshold) { choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); - } else if (heap->mode()->is_generational()) { - adjust_reserves_for_abbreviated(heap); + } else { + prepare_for_abbreviated_cycle(); } + collection_set->summarize(total_garbage, immediate_garbage, immediate_regions); ShenandoahTracer::report_evacuation_info(collection_set, free_regions, immediate_regions, immediate_garbage); } @@ -163,13 +164,6 @@ void ShenandoahHeuristics::start_idle_span() { // do nothing } -void ShenandoahHeuristics::adjust_reserves_for_abbreviated(ShenandoahHeap* heap) { - // We are not going to evacuate because this is an abbreviated cycle. Reset the reserves. - heap->young_generation()->set_evacuation_reserve(0UL); - heap->old_generation()->set_evacuation_reserve(0UL); - heap->old_generation()->set_promoted_reserve(0UL); -} - void ShenandoahHeuristics::record_degenerated_cycle_start(bool out_of_cycle) { if (out_of_cycle) { _precursor_cycle_start = _cycle_start = os::elapsedTime(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index b50c20042625..1deb98c3f8a9 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -83,9 +83,6 @@ class ShenandoahHeuristics : public CHeapObj { double _most_recent_trigger_evaluation_time; double _most_recent_planned_sleep_interval; - // When we decide to do an abbreviated cycle, withdraw reserves so memory can be made available to mutators. - void adjust_reserves_for_abbreviated(ShenandoahHeap* heap); - protected: static constexpr uint Moving_Average_Samples = 10; // Number of samples to store in moving averages @@ -196,6 +193,9 @@ class ShenandoahHeuristics : public CHeapObj { RegionData* data, size_t data_size, size_t free) = 0; + // Called when immediate garbage threshold is reached. + virtual void prepare_for_abbreviated_cycle() {} + virtual void adjust_penalty(intx step); inline void accept_trigger() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 5636dee3ae2d..8cc8e31cf291 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -189,6 +189,13 @@ class ShenandoahAgeCensus: public CHeapObj { // Visible for testing. Use is_tenurable for consistent tenuring comparisons. uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } + // Returns zero when always_tenure is true (which is only true when the gc + // is triggered by WB.fullGC()). Note that zero itself is the floor, so do + // not subtract from it to get the younger cohort. + uint effective_threshold() const { + return is_always_tenure() ? 0 : tenuring_threshold(); + } + // Return true if this age is at or above the tenuring threshold, or if always tenure is enabled. bool is_tenurable(uint age) const { return age >= tenuring_threshold() || _always_tenure; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index c377ef8b0edd..98fc9040df96 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -514,6 +514,7 @@ class ShenandoahHeapRegion { } void reset_age() { + assert(get_top_before_promote() == nullptr, "Cannot reset age on region (%zu) scheduled for promotion", index()); CENSUS_NOISE(_youth += _age;) _age = 0; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp index ffa087ac3c0e..4a3c2b9f2e30 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp @@ -39,7 +39,6 @@ ShenandoahInPlacePromotionPlanner::ShenandoahInPlacePromotionPlanner(const Shena , _marking_context(_heap->marking_context()) , _mutator_regions(_free_set) , _collector_regions(_free_set) - , _pip_padding_bytes(0) { } @@ -105,7 +104,6 @@ void ShenandoahInPlacePromotionPlanner::prepare(ShenandoahHeapRegion* r) { remnant_bytes = 0; } - _pip_padding_bytes += remnant_bytes; _free_set->prepare_to_promote_in_place(i, remnant_bytes); } else { // Since the remnant is so small that this region has already been retired, we don't have to worry about any @@ -117,7 +115,6 @@ void ShenandoahInPlacePromotionPlanner::prepare(ShenandoahHeapRegion* r) { } void ShenandoahInPlacePromotionPlanner::complete_planning() const { - _heap->old_generation()->set_pad_for_promote_in_place(_pip_padding_bytes); _heap->old_generation()->set_expected_humongous_region_promotions(_pip_humongous_stats.count); _heap->old_generation()->set_expected_regular_region_promotions(_pip_regular_stats.count); log_info(gc, ergo)("Planning to promote in place %zu humongous regions and %zu" @@ -136,30 +133,31 @@ void ShenandoahInPlacePromotionPlanner::complete_planning() const { } void ShenandoahInPlacePromoter::maybe_promote_region(ShenandoahHeapRegion* r) const { - if (r->is_young() && r->is_active() && _heap->is_tenurable(r)) { - if (r->is_humongous_start()) { - // We promote humongous_start regions along with their affiliated continuations during evacuation rather than - // doing this work during a safepoint. We cannot put humongous regions into the collection set because that - // triggers the load-reference barrier (LRB) to copy on reference fetch. - // - // Aged humongous continuation regions are handled with their start region. If an aged regular region has - // more garbage than ShenandoahOldGarbageThreshold, we'll promote by evacuation. If there is room for evacuation - // in this cycle, the region will be in the collection set. If there is no room, the region will be promoted - // by evacuation in some future GC cycle. - - // We do not promote primitive arrays because there's no performance penalty keeping them in young. When/if they - // become garbage, reclaiming the memory from young is much quicker and more efficient than reclaiming them from old. - oop obj = cast_to_oop(r->bottom()); - if (!obj->is_typeArray()) { - promote_humongous(r); - } - } else if (r->is_regular_or_regular_pinned() && (r->get_top_before_promote() != nullptr)) { - // Likewise, we cannot put promote-in-place regions into the collection set because that would also trigger - // the LRB to copy on reference fetch. - // - // If an aged regular region has received allocations during the current cycle, we do not promote because the - // newly allocated objects do not have appropriate age; this region's age will be reset to zero at end of cycle. - promote(r); + if (r->is_regular_or_regular_pinned() && (r->get_top_before_promote() != nullptr)) { + // This region was scheduled for promotion. The promotion must be completed. + // The 'always_tenure' override flag set by WB.fullGC() is not carried over + // into the degenerated cycle so we cannot rely on is_tenurable again. We checked + // it when we made the plan for this region, that plan is authoritative. + assert(r->is_young() && r->is_active(), "Region scheduled for promotion must still be young and active"); + promote(r); + return; + } + + if (r->is_young() && r->is_active() && r->is_humongous_start() && _heap->is_tenurable(r)) { + // We promote humongous_start regions along with their affiliated continuations during evacuation rather than + // doing this work during a safepoint. We cannot put humongous regions into the collection set because that + // triggers the load-reference barrier (LRB) to copy on reference fetch. + // + // Aged humongous continuation regions are handled with their start region. If an aged regular region has + // more garbage than ShenandoahOldGarbageThreshold, we'll promote by evacuation. If there is room for evacuation + // in this cycle, the region will be in the collection set. If there is no room, the region will be promoted + // by evacuation in some future GC cycle. + + // We do not promote primitive arrays because there's no performance penalty keeping them in young. When/if they + // become garbage, reclaiming the memory from young is much quicker and more efficient than reclaiming them from old. + oop obj = cast_to_oop(r->bottom()); + if (!obj->is_typeArray()) { + promote_humongous(r); } } } @@ -182,7 +180,6 @@ void ShenandoahInPlacePromoter::promote(ShenandoahHeapRegion* region) const { "Region %zu has too much garbage for promotion", region->index()); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_regular_or_regular_pinned(), "Use different service to promote humongous regions"); - assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); assert(region->get_top_before_promote() == tams, "Region %zu has been used for allocations before promotion", region->index()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp index d2cb644a59eb..4777c1893e3f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp @@ -84,7 +84,7 @@ class ShenandoahInPlacePromotionPlanner { RegionPromotionStats() : count(0), usage(0), free(0), garbage(0) {} void update(ShenandoahHeapRegion* region) { count++; - usage += region->used(); + usage += region->get_live_data_bytes(); free += region->free(); garbage += region->garbage(); } @@ -101,9 +101,6 @@ class ShenandoahInPlacePromotionPlanner { RegionPromotions _mutator_regions; RegionPromotions _collector_regions; - // Tracks the padding of space above top in regions eligible for promotion in place - size_t _pip_padding_bytes; - // Tracks stats for in place promotions RegionPromotionStats _pip_regular_stats; RegionPromotionStats _pip_humongous_stats; @@ -124,6 +121,11 @@ class ShenandoahInPlacePromotionPlanner { const RegionPromotionStats& humongous_region_stats() const { return _pip_humongous_stats; } size_t old_garbage_threshold() const { return _old_garbage_threshold; } + + // Return the total amount of live bytes that will be promoted in place + size_t live_bytes() const { + return regular_region_stats().usage + humongous_region_stats().usage; + } }; // For regions that have been selected and prepared for promotion, this class diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 958e7b3cf956..8d34937218ec 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -109,7 +109,6 @@ ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues) _promoted_reserve(0), _promoted_expended(0), _promotion_potential(0), - _pad_for_promote_in_place(0), _promotable_humongous_regions(0), _promotable_regular_regions(0), _is_parsable(true), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 61a3114f906b..3519303c3037 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -74,11 +74,6 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { // It is also used when computing the optimum size for the old generation. size_t _promotion_potential; - // When a region is selected to be promoted in place, the remaining free memory is filled - // in to prevent additional allocations (preventing premature promotion of newly allocated - // objects). This field records the total amount of padding used for such regions. - size_t _pad_for_promote_in_place; - // During construction of the collection set, we keep track of regions that are eligible // for promotion in place. These fields track the count of those humongous and regular regions. // This data is used to force the evacuation phase even when the collection set is otherwise @@ -153,10 +148,6 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { void set_promotion_potential(size_t val) { _promotion_potential = val; } size_t get_promotion_potential() const { return _promotion_potential; } - // See description in field declaration - void set_pad_for_promote_in_place(size_t pad) { _pad_for_promote_in_place = pad; } - size_t get_pad_for_promote_in_place() const { return _pad_for_promote_in_place; } - // See description in field declaration void set_expected_humongous_region_promotions(size_t region_count) { _promotable_humongous_regions = region_count; } void set_expected_regular_region_promotions(size_t region_count) { _promotable_regular_regions = region_count; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp index c28e572dd6bd..40b9c94737e1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp @@ -23,6 +23,7 @@ */ #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" +#include "gc/shenandoah/shenandoahInPlacePromoter.hpp" #include "gc/shenandoah/shenandoahTrace.hpp" #include "jfr/jfrEvents.hpp" @@ -43,22 +44,19 @@ void ShenandoahTracer::report_evacuation_info(const ShenandoahCollectionSet* cse } } -void ShenandoahTracer::report_promotion_info(const ShenandoahCollectionSet* cset, - size_t regions_promoted_humongous, size_t humongous_promoted_garbage, size_t humongous_promoted_free, - size_t regions_promoted_regular, size_t regular_promoted_garbage, size_t regular_promoted_free) { - +void ShenandoahTracer::report_promotion_info(const ShenandoahCollectionSet* cset, const ShenandoahInPlacePromotionPlanner& planner) { EventShenandoahPromotionInformation e; if (e.should_commit()) { e.set_gcId(GCId::current()); e.set_collectedOld(cset->get_live_bytes_in_old_regions()); e.set_collectedPromoted(cset->get_live_bytes_in_tenurable_regions()); e.set_collectedYoung(cset->get_live_bytes_in_untenurable_regions()); - e.set_regionsPromotedHumongous(regions_promoted_humongous); - e.set_humongousPromotedGarbage(humongous_promoted_garbage); - e.set_humongousPromotedFree(humongous_promoted_free); - e.set_regionsPromotedRegular(regions_promoted_regular); - e.set_regularPromotedGarbage(regular_promoted_garbage); - e.set_regularPromotedFree(regular_promoted_free); + e.set_regionsPromotedHumongous(planner.humongous_region_stats().count); + e.set_humongousPromotedGarbage(planner.humongous_region_stats().garbage); + e.set_humongousPromotedFree(planner.humongous_region_stats().free); + e.set_regionsPromotedRegular(planner.regular_region_stats().count); + e.set_regularPromotedGarbage(planner.regular_region_stats().garbage); + e.set_regularPromotedFree(planner.regular_region_stats().free); e.commit(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp index e5c80e0705fe..b37e8d669959 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" class ShenandoahCollectionSet; +class ShenandoahInPlacePromotionPlanner; class ShenandoahTracer : public GCTracer, public CHeapObj { public: @@ -39,9 +40,7 @@ class ShenandoahTracer : public GCTracer, public CHeapObj { size_t free_regions, size_t regions_immediate, size_t immediate_size); // Sends a JFR event summarizing in-place promotion activity (generational mode only) - static void report_promotion_info(const ShenandoahCollectionSet* cset, - size_t regions_promoted_humongous, size_t humongous_promoted_garbage, size_t humongous_promoted_free, - size_t regions_promoted_regular, size_t regular_promoted_garbage, size_t regular_promoted_free); + static void report_promotion_info(const ShenandoahCollectionSet* cset, const ShenandoahInPlacePromotionPlanner& planner); }; #endif diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestPromoteInPlaceDuringAbbreviatedCycle.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestPromoteInPlaceDuringAbbreviatedCycle.java new file mode 100644 index 000000000000..e9be9f39fbd1 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestPromoteInPlaceDuringAbbreviatedCycle.java @@ -0,0 +1,225 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package gc.shenandoah.generational; + +import com.sun.management.GarbageCollectionNotificationInfo; + +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.TimeUnit; + +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.openmbean.CompositeData; + +import jdk.test.whitebox.WhiteBox; + + +/* + * @test id=generational + * @bug 8390310 + * @requires vm.gc.Shenandoah + * @summary Aged regions must be promoted in place during an abbreviated cycle + * (one that skips the evacuation and update-refs phases). + * @library /testlibrary /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. + * -Xms512m -Xmx512m + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:ShenandoahGenerationalMinPIPUsage=1 + * -XX:ShenandoahOldGarbageThreshold=100 + * -XX:ShenandoahRegionSize=1m + * -XX:ShenandoahImmediateThreshold=0 + * -XX:ShenandoahGenerationalMinTenuringAge=1 + * -XX:ShenandoahGenerationalMaxTenuringAge=1 + * -XX:-DisableExplicitGC -XX:+ExplicitGCInvokesConcurrent + * gc.shenandoah.generational.TestPromoteInPlaceDuringAbbreviatedCycle + */ + + /* + * @test id=generational-always-tenure + * @bug 8390310 + * @requires vm.gc.Shenandoah + * @summary Tests that promotion potential is correct when the always tenure + * override is in effect (set by WB.fullGC()) + * @library /testlibrary /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. + * -Xms512m -Xmx512m + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:ShenandoahGenerationalMinPIPUsage=1 + * -XX:ShenandoahOldGarbageThreshold=100 + * -XX:ShenandoahRegionSize=1m + * -XX:ShenandoahImmediateThreshold=0 + * -XX:ShenandoahGenerationalMinTenuringAge=2 + * -XX:ShenandoahGenerationalMaxTenuringAge=2 + * -XX:-DisableExplicitGC -XX:+ExplicitGCInvokesConcurrent + * gc.shenandoah.generational.TestPromoteInPlaceDuringAbbreviatedCycle always-tenure + */ +public class TestPromoteInPlaceDuringAbbreviatedCycle { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + // Make a humongous array (with 1MB regions, this will be humongous with + // and without compressed oops). + private static final int HUMONGOUS_REFS = 512 * 1024; + + // Also make a not humongous array to test regular region promotion path + private static final int REGULAR_REFS = 256; + + // Used to create pure garbage regions to satisfy immediate garbage + // threshold + private static final int GARBAGE_BYTES = 2 * 1024 * 1024; + + // Test will fail if our humongous object isn't promoted in this many cycles + private static final int MAX_CYCLES = 5; + + // Keep references so the arrays under test stay live and age in young. + private static Object[] humongous; + private static Object[] regular; + + // Reference used to publish, then drop, the per-cycle garbage (to keep + // local var from being eliminated) + private static Object garbage; + + private static boolean isCollectorNotification(Notification n) { + return n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION); + } + + private static boolean isIllegalPause(GarbageCollectionNotificationInfo info) { + return info.getGcName().equals("Shenandoah Pauses") + && (info.getGcAction().contains("Update Refs") + || info.getGcAction().contains("Degen") + || info.getGcAction().contains("Full")); + } + + private static void subscribeToCollectorNotifications(NotificationListener listener) { + for (GarbageCollectorMXBean b : ManagementFactory.getGarbageCollectorMXBeans()) { + ((NotificationEmitter) b).addNotificationListener(listener, null, null); + } + } + + private static void unsubscribeToCollectorNotifications(NotificationListener listener) throws Exception { + for (GarbageCollectorMXBean b : ManagementFactory.getGarbageCollectorMXBeans()) { + ((NotificationEmitter) b).removeNotificationListener(listener, null, null); + } + } + + private static GarbageCollectorMXBean cycleBean() { + for (GarbageCollectorMXBean b : ManagementFactory.getGarbageCollectorMXBeans()) { + if (b.getName().equals("Shenandoah Cycles")) { + return b; + } + } + throw new IllegalStateException("No \"Shenandoah Cycles\" bean found"); + } + + public static void main(String[] args) throws Exception { + boolean alwaysTenure = args.length > 0 && "always-tenure".equals(args[0]); + humongous = new Object[HUMONGOUS_REFS]; + regular = new Object[REGULAR_REFS]; + + // Listen for events to detect if a non-abbreviated cycle runs + final GarbageCollectorMXBean cycles = cycleBean(); + final AtomicLong illegalPauses = new AtomicLong(); + final AtomicLong maxCycleId = new AtomicLong(); + NotificationListener listener = (Notification n, Object o) -> { + if (isCollectorNotification(n)) { + GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); + if (isIllegalPause(info)) { + illegalPauses.incrementAndGet(); + } else if (info.getGcName().equals("Shenandoah Cycles")) { + long gcId = info.getGcInfo().getId(); + if (gcId > maxCycleId.get()) { + maxCycleId.set(gcId); + } + } + } + }; + + subscribeToCollectorNotifications(listener); + + if (WB.isObjectInOldGen(humongous)) { + throw new IllegalStateException("Expected young humongous array"); + } + + if (WB.isObjectInOldGen(regular)) { + throw new IllegalStateException("Expected young regular array"); + } + + for (int cycle = 1; cycle <= MAX_CYCLES; cycle++) { + // Produce one whole dead region so the upcoming cycle is abbreviated. + garbage = new byte[GARBAGE_BYTES]; + garbage = null; + + if (alwaysTenure) { + // This also runs a global cycle, but with an effective tenuring threshold of zero + WB.fullGC(); + } else { + // Runs a concurrent global cycle and blocks until it completes. + System.gc(); + } + + // Both objects are in old, exit the test loop + if (WB.isObjectInOldGen(humongous) && WB.isObjectInOldGen(regular)) { + break; + } + } + + // Flush gc notification events + long targetCycles = cycles.getCollectionCount(); + long deadlineNanos = System.nanoTime() + TimeUnit.SECONDS.toNanos(30); + while (maxCycleId.get() < targetCycles) { + if (System.nanoTime() > deadlineNanos) { + throw new RuntimeException("Timed out flushing GC notifications: delivered " + + maxCycleId.get() + " of " + + targetCycles + " cycle notifications"); + } + Thread.sleep(10); + } + + unsubscribeToCollectorNotifications(listener); + + if (illegalPauses.get() != 0) { + throw new RuntimeException(illegalPauses.get() + " non-abbreviated cycles happened"); + } + + if (!WB.isObjectInOldGen(humongous)) { + throw new RuntimeException("Humongous region was not promoted in place."); + } + + if (!WB.isObjectInOldGen(regular)) { + throw new RuntimeException("Regular region was not promoted in place"); + } + } +} From 6f2087e93405040d3c036be4391702c759cb9734 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Fri, 21 Aug 2026 05:08:51 +0000 Subject: [PATCH 014/223] 8389610: ARM32: native method wrapper unlocks a stale oop after GC relocates the object Reviewed-by: bulasevich, fbredberg --- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index d0fba14d8aa4..d471cf6ce334 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1292,6 +1292,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label slow_unlock, unlock_done; if (method->is_synchronized()) { + // Get locked oop from the handle we passed to jni + __ ldr(sync_obj, Address(sync_handle)); + log_trace(fastlock)("SharedRuntime unlock fast"); __ fast_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */, 7 /* savemask */, slow_unlock); From 0e10d3c382d66b31128a735daa92bfc670178a41 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Fri, 21 Aug 2026 05:32:41 +0000 Subject: [PATCH 015/223] 8390499: Clean up suspicious bailout in ciMethod::find_monomorphic_target Reviewed-by: dlong, vlivanov --- src/hotspot/share/ci/ciMethod.cpp | 12 +-- .../packagePrivate/NonOverridenParent.java | 33 +++++++ .../cha/packagePrivate/OverridenParent.java | 33 +++++++ .../cha/packagePrivate/OverridingChild.java | 39 ++++++++ .../TestDevirtualizePackageMethod.java | 97 +++++++++++++++++++ .../differentPackage/NonOverridingChild.java | 40 ++++++++ 6 files changed, 243 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/cha/packagePrivate/NonOverridenParent.java create mode 100644 test/hotspot/jtreg/compiler/cha/packagePrivate/OverridenParent.java create mode 100644 test/hotspot/jtreg/compiler/cha/packagePrivate/OverridingChild.java create mode 100644 test/hotspot/jtreg/compiler/cha/packagePrivate/TestDevirtualizePackageMethod.java create mode 100644 test/hotspot/jtreg/compiler/cha/packagePrivate/differentPackage/NonOverridingChild.java diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index be5c6182d9f8..db4bf40271a6 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -820,17 +820,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, if (target() == root_m->get_Method()) { return root_m; } - if (!root_m->is_public() && - !root_m->is_protected()) { - // If we are going to reason about inheritance, it's easiest - // if the method in question is public, protected, or private. - // If the answer is not root_m, it is conservatively correct - // to return null, even if the CHA encountered irrelevant - // methods in other packages. - // %%% TO DO: Work out logic for package-private methods - // with the same name but different vtable indexes. - return nullptr; - } + return CURRENT_THREAD_ENV->get_method(target()); } diff --git a/test/hotspot/jtreg/compiler/cha/packagePrivate/NonOverridenParent.java b/test/hotspot/jtreg/compiler/cha/packagePrivate/NonOverridenParent.java new file mode 100644 index 000000000000..560fff00b6d7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/packagePrivate/NonOverridenParent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.cha.packagePrivate; + +/** + * An abstract class such that all of its concrete subclasses have a single implementation of + * {@link #call}. The subclasses lie in a different package so they cannot override {@link #call}. + */ +public abstract class NonOverridenParent { + int call() { + return 0; + } +} diff --git a/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridenParent.java b/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridenParent.java new file mode 100644 index 000000000000..0c156a485ccc --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridenParent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.cha.packagePrivate; + +/** + * An abstract class such that all of its concrete subclasses have a single implementation of + * {@link #call} that is defined in a subclass of this class. + */ +public abstract class OverridenParent { + int call() { + return 0; + } +} diff --git a/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridingChild.java b/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridingChild.java new file mode 100644 index 000000000000..9877286662f5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/packagePrivate/OverridingChild.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.cha.packagePrivate; + +/** + * This class provides the unique implementation for {@link OverridenParent#call}, it is abstract + * so that {@code ciInstanceKlass::unique_concrete_subklass} does not find it. + */ +public abstract class OverridingChild extends OverridenParent { + // 3 concrete implementations to defeat the bimorphic inlining heuristic + public static class GrandChild1 extends OverridingChild {} + public static class GrandChild2 extends OverridingChild {} + public static class GrandChild3 extends OverridingChild {} + + @Override + int call() { + return 1; + } +} diff --git a/test/hotspot/jtreg/compiler/cha/packagePrivate/TestDevirtualizePackageMethod.java b/test/hotspot/jtreg/compiler/cha/packagePrivate/TestDevirtualizePackageMethod.java new file mode 100644 index 000000000000..22f987baaa3e --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/packagePrivate/TestDevirtualizePackageMethod.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.cha.packagePrivate; + +import compiler.cha.packagePrivate.differentPackage.NonOverridingChild; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8390499 + * @summary Verify that C2 correctly devirtualizes package-private methods. + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestDevirtualizePackageMethod { + public static void main(String[] args) { + var framework = new TestFramework(); + framework.setDefaultWarmup(1); + framework.addFlags("-XX:CompileCommand=dontinline,*::call"); + framework.start(); + } + + @Run(test = {"testOverriding1", "testOverriding2"}) + public void runOverriding() { + var v1 = new OverridingChild.GrandChild1(); + var v2 = new OverridingChild.GrandChild2(); + var v3 = new OverridingChild.GrandChild3(); + Asserts.assertEQ(1, testOverriding1(v1)); + Asserts.assertEQ(1, testOverriding1(v2)); + Asserts.assertEQ(1, testOverriding1(v3)); + Asserts.assertEQ(1, testOverriding2(v1)); + Asserts.assertEQ(1, testOverriding2(v2)); + Asserts.assertEQ(1, testOverriding2(v3)); + } + + @Test + @IR(failOn = {IRNode.DYNAMIC_CALL_OF_METHOD, "OverridenParent::call", IRNode.DYNAMIC_CALL_OF_METHOD, "OverridingChild::call"}) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "OverridingChild::call", "1"}) + private static int testOverriding1(OverridenParent v) { + return v.call(); + } + + @Test + @IR(failOn = {IRNode.DYNAMIC_CALL_OF_METHOD, "OverridenParent::call", IRNode.DYNAMIC_CALL_OF_METHOD, "OverridingChild::call"}) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "OverridingChild::call", "1"}) + private static int testOverriding2(OverridingChild v) { + return v.call(); + } + + @Run(test = {"testNonOverriding1", "testNonOverriding2"}) + public void runNonOverriding() { + var v1 = new NonOverridingChild.GrandChild1(); + var v2 = new NonOverridingChild.GrandChild2(); + var v3 = new NonOverridingChild.GrandChild3(); + Asserts.assertEQ(0, testNonOverriding1(v1)); + Asserts.assertEQ(0, testNonOverriding1(v2)); + Asserts.assertEQ(0, testNonOverriding1(v3)); + Asserts.assertEQ(1, testNonOverriding2(v1)); + Asserts.assertEQ(1, testNonOverriding2(v2)); + Asserts.assertEQ(1, testNonOverriding2(v3)); + } + + @Test + @IR(failOn = {IRNode.DYNAMIC_CALL_OF_METHOD, "NonOverridenParent::call", IRNode.DYNAMIC_CALL_OF_METHOD, "NonOverridingChild::call"}) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "NonOverridenParent::call", "1"}) + private static int testNonOverriding1(NonOverridenParent v) { + return v.call(); + } + + @Test + @IR(failOn = {IRNode.DYNAMIC_CALL_OF_METHOD, "NonOverridenParent::call", IRNode.DYNAMIC_CALL_OF_METHOD, "NonOverridingChild::call"}) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "NonOverridingChild::call", "1"}) + private static int testNonOverriding2(NonOverridingChild v) { + return v.call(); + } +} diff --git a/test/hotspot/jtreg/compiler/cha/packagePrivate/differentPackage/NonOverridingChild.java b/test/hotspot/jtreg/compiler/cha/packagePrivate/differentPackage/NonOverridingChild.java new file mode 100644 index 000000000000..337b308f873b --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/packagePrivate/differentPackage/NonOverridingChild.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.cha.packagePrivate.differentPackage; + +import compiler.cha.packagePrivate.NonOverridenParent; + +/** + * Although this class also has {@link #call}, it does not override + * {@link NonOverridenParent#call}. + */ +public abstract class NonOverridingChild extends NonOverridenParent { + // 3 subclasses to defeat the bimorphic inlining heuristic + public static class GrandChild1 extends NonOverridingChild {} + public static class GrandChild2 extends NonOverridingChild {} + public static class GrandChild3 extends NonOverridingChild {} + + public int call() { + return 1; + } +} From bb40c338cd6f0942f6b233bf9655613ff261934e Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Fri, 21 Aug 2026 08:20:31 +0000 Subject: [PATCH 016/223] 8387204: C2 VectorAPI: logic cones wrongly treats masked XorV Reviewed-by: xgong, vlivanov, mhaessig --- src/hotspot/share/opto/compile.cpp | 12 +- .../vectorapi/TestMaskedMacroLogicVector.java | 361 +++++++++++++++++- 2 files changed, 368 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e12eec300899..14036abc9809 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3425,8 +3425,12 @@ bool Compile::has_vbox_nodes() { //---------------------------- Bitwise operation packing optimization --------------------------- static bool is_vector_unary_bitwise_op(Node* n) { - return n->Opcode() == Op_XorV && - VectorNode::is_vector_bitwise_not_pattern(n); + // A masked XorV not-pattern is NOT unary: on inactive lanes the masked + // operation keeps its first operand, so both inputs must be preserved (and + // their order matters, since in(1) becomes the masked MacroLogicV + // passthrough). Only an unmasked not-pattern is genuinely unary. +return VectorNode::is_vector_bitwise_not_pattern(n) && + !n->is_predicated_vector(); } static bool is_vector_binary_bitwise_op(Node* n) { @@ -3469,7 +3473,7 @@ static uint collect_unique_inputs(Node* n, Unique_Node_List& inputs) { uint cnt = 0; if (is_vector_bitwise_op(n)) { uint inp_cnt = n->is_predicated_vector() ? n->req()-1 : n->req(); - if (VectorNode::is_vector_bitwise_not_pattern(n)) { + if (is_vector_unary_bitwise_op(n)) { assert(n->req() == (n->is_predicated_vector() ? 4 : 3), "must have 2 data inputs"); Node* opnd = VectorNode::is_all_ones_vector(n->in(1)) ? n->in(2) : n->in(1); if (!inputs.member(opnd)) { @@ -3630,7 +3634,7 @@ uint Compile::compute_truth_table(Unique_Node_List& partition, Unique_Node_List& res = func1 & func2; break; case Op_XorV: - if (VectorNode::is_vector_bitwise_not_pattern(n)) { + if (is_vector_unary_bitwise_op(n)) { assert(func2 == 0 && func3 == 0, "not unary"); res = (~func1) & 0xFF; } else { diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java index 22c35d80c70c..74d650d07a14 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestMaskedMacroLogicVector.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8273322 8387145 + * @bug 8273322 8387145 8387204 * @key randomness * @summary Enhance macro logic optimization for masked logic operations. * @modules jdk.incubator.vector @@ -646,6 +646,137 @@ public void verifyInt11(int[] r, int[] a, int[] b, int[] c, boolean [] mask, boo } } + static int intFunc12(int a, int b, boolean mask) { + int left = mask ? (-1 ^ a) : -1; + return mask ? (left | b) : left; + } + + @ForceInline + public void testInt12Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector vall = IntVector.broadcast(SPECIES, -1); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.OR, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt12_Int128(int[] r, int[] a, int[] b, boolean [] mask) { + testInt12Kernel(IntVector.SPECIES_128, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt12_Int256(int[] r, int[] a, int[] b, boolean [] mask) { + testInt12Kernel(IntVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt12_Int512(int[] r, int[] a, int[] b, boolean [] mask) { + testInt12Kernel(IntVector.SPECIES_512, r, a, b, mask); + } + + public void verifyInt12(int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc12(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt12: at #%d: r=%d, expected = %d = intFunc12(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } + + static int intFunc13(int a, int b, boolean mask) { + int left = mask ? (-1 ^ a) : -1; + return mask ? (left & b) : left; + } + + @ForceInline + public void testInt13Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector vall = IntVector.broadcast(SPECIES, -1); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.AND, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt13_Int128(int[] r, int[] a, int[] b, boolean [] mask) { + testInt13Kernel(IntVector.SPECIES_128, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt13_Int256(int[] r, int[] a, int[] b, boolean [] mask) { + testInt13Kernel(IntVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt13_Int512(int[] r, int[] a, int[] b, boolean [] mask) { + testInt13Kernel(IntVector.SPECIES_512, r, a, b, mask); + } + + public void verifyInt13(int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc13(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt13: at #%d: r=%d, expected = %d = intFunc13(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } + + static int intFunc14(int a, int b, boolean mask) { + int left = mask ? (-1 ^ a) : -1; + return mask ? (left ^ b) : left; + } + + @ForceInline + public void testInt14Kernel(VectorSpecies SPECIES, int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + IntVector vall = IntVector.broadcast(SPECIES, -1); + IntVector va = IntVector.fromArray(SPECIES, a, i); + IntVector vb = IntVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.XOR, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt14_Int128(int[] r, int[] a, int[] b, boolean [] mask) { + testInt14Kernel(IntVector.SPECIES_128, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt14_Int256(int[] r, int[] a, int[] b, boolean [] mask) { + testInt14Kernel(IntVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testInt14_Int512(int[] r, int[] a, int[] b, boolean [] mask) { + testInt14Kernel(IntVector.SPECIES_512, r, a, b, mask); + } + + public void verifyInt14(int[] r, int[] a, int[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + int expected = intFunc14(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testInt14: at #%d: r=%d, expected = %d = intFunc14(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } // ===================================================== // @@ -695,6 +826,123 @@ public void verifyLong(long[] r, long[] a, long[] b, long[] c) { } } + static long longFunc15(long a, long b, boolean mask) { + long left = mask ? (-1L ^ a) : -1L; + return mask ? (left | b) : left; + } + + @ForceInline + public void testLong15Kernel(VectorSpecies SPECIES, long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + LongVector vall = LongVector.broadcast(SPECIES, -1L); + LongVector va = LongVector.fromArray(SPECIES, a, i); + LongVector vb = LongVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.OR, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong15_Long256(long[] r, long[] a, long[] b, boolean [] mask) { + testLong15Kernel(LongVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong15_Long512(long[] r, long[] a, long[] b, boolean [] mask) { + testLong15Kernel(LongVector.SPECIES_512, r, a, b, mask); + } + + public void verifyLong15(long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + long expected = longFunc15(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testLong15: at #%d: r=%d, expected = %d = longFunc15(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } + + static long longFunc16(long a, long b, boolean mask) { + long left = mask ? (-1L ^ a) : -1L; + return mask ? (left & b) : left; + } + + @ForceInline + public void testLong16Kernel(VectorSpecies SPECIES, long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + LongVector vall = LongVector.broadcast(SPECIES, -1L); + LongVector va = LongVector.fromArray(SPECIES, a, i); + LongVector vb = LongVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.AND, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong16_Long256(long[] r, long[] a, long[] b, boolean [] mask) { + testLong16Kernel(LongVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong16_Long512(long[] r, long[] a, long[] b, boolean [] mask) { + testLong16Kernel(LongVector.SPECIES_512, r, a, b, mask); + } + + public void verifyLong16(long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + long expected = longFunc16(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testLong16: at #%d: r=%d, expected = %d = longFunc16(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } + + static long longFunc17(long a, long b, boolean mask) { + long left = mask ? (-1L ^ a) : -1L; + return mask ? (left ^ b) : left; + } + + @ForceInline + public void testLong17Kernel(VectorSpecies SPECIES, long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < SPECIES.loopBound(r.length); i += SPECIES.length()) { + VectorMask vmask = VectorMask.fromArray(SPECIES, mask , i); + LongVector vall = LongVector.broadcast(SPECIES, -1L); + LongVector va = LongVector.fromArray(SPECIES, a, i); + LongVector vb = LongVector.fromArray(SPECIES, b, i); + vall.lanewise(VectorOperators.XOR, va, vmask) + .lanewise(VectorOperators.XOR, vb, vmask) + .intoArray(r, i); + } + } + + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong17_Long256(long[] r, long[] a, long[] b, boolean [] mask) { + testLong17Kernel(LongVector.SPECIES_256, r, a, b, mask); + } + @Test + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + public void testLong17_Long512(long[] r, long[] a, long[] b, boolean [] mask) { + testLong17Kernel(LongVector.SPECIES_512, r, a, b, mask); + } + + public void verifyLong17(long[] r, long[] a, long[] b, boolean [] mask) { + for (int i = 0; i < r.length; i++) { + long expected = longFunc17(a[i], b[i], mask[i]); + if (r[i] != expected) { + throw new AssertionError(String.format("testLong17: at #%d: r=%d, expected = %d = longFunc17(%d,%d,%b)", + i, r[i], expected, a[i], b[i], mask[i])); + } + } + } + // ===================================================== // private static final Random R = Utils.getRandomInstance(); @@ -1006,6 +1254,72 @@ public void kernel_testInt11_Int512() { } } + @Run(test = {"testInt12_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt12_Int128() { + for (int i = 0; i < 10000; i++) { + testInt12_Int128(r, a, b, mask); + verifyInt12(r, a, b, mask); + } + } + @Run(test = {"testInt12_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt12_Int256() { + for (int i = 0; i < 10000; i++) { + testInt12_Int256(r, a, b, mask); + verifyInt12(r, a, b, mask); + } + } + @Run(test = {"testInt12_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt12_Int512() { + for (int i = 0; i < 10000; i++) { + testInt12_Int512(r, a, b, mask); + verifyInt12(r, a, b, mask); + } + } + + @Run(test = {"testInt13_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt13_Int128() { + for (int i = 0; i < 10000; i++) { + testInt13_Int128(r, a, b, mask); + verifyInt13(r, a, b, mask); + } + } + @Run(test = {"testInt13_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt13_Int256() { + for (int i = 0; i < 10000; i++) { + testInt13_Int256(r, a, b, mask); + verifyInt13(r, a, b, mask); + } + } + @Run(test = {"testInt13_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt13_Int512() { + for (int i = 0; i < 10000; i++) { + testInt13_Int512(r, a, b, mask); + verifyInt13(r, a, b, mask); + } + } + + @Run(test = {"testInt14_Int128"}, mode = RunMode.STANDALONE) + public void kernel_testInt14_Int128() { + for (int i = 0; i < 10000; i++) { + testInt14_Int128(r, a, b, mask); + verifyInt14(r, a, b, mask); + } + } + @Run(test = {"testInt14_Int256"}, mode = RunMode.STANDALONE) + public void kernel_testInt14_Int256() { + for (int i = 0; i < 10000; i++) { + testInt14_Int256(r, a, b, mask); + verifyInt14(r, a, b, mask); + } + } + @Run(test = {"testInt14_Int512"}, mode = RunMode.STANDALONE) + public void kernel_testInt14_Int512() { + for (int i = 0; i < 10000; i++) { + testInt14_Int512(r, a, b, mask); + verifyInt14(r, a, b, mask); + } + } + @Run(test = {"testLong_Long256"}, mode = RunMode.STANDALONE) public void kernel_testLong_Long256() { for (int i = 0; i < 10000; i++) { @@ -1021,6 +1335,51 @@ public void kernel_testLong_Long512() { } } + @Run(test = {"testLong15_Long256"}, mode = RunMode.STANDALONE) + public void kernel_testLong15_Long256() { + for (int i = 0; i < 10000; i++) { + testLong15_Long256(rl, al, bl, mask); + verifyLong15(rl, al, bl, mask); + } + } + @Run(test = {"testLong15_Long512"}, mode = RunMode.STANDALONE) + public void kernel_testLong15_Long512() { + for (int i = 0; i < 10000; i++) { + testLong15_Long512(rl, al, bl, mask); + verifyLong15(rl, al, bl, mask); + } + } + + @Run(test = {"testLong16_Long256"}, mode = RunMode.STANDALONE) + public void kernel_testLong16_Long256() { + for (int i = 0; i < 10000; i++) { + testLong16_Long256(rl, al, bl, mask); + verifyLong16(rl, al, bl, mask); + } + } + @Run(test = {"testLong16_Long512"}, mode = RunMode.STANDALONE) + public void kernel_testLong16_Long512() { + for (int i = 0; i < 10000; i++) { + testLong16_Long512(rl, al, bl, mask); + verifyLong16(rl, al, bl, mask); + } + } + + @Run(test = {"testLong17_Long256"}, mode = RunMode.STANDALONE) + public void kernel_testLong17_Long256() { + for (int i = 0; i < 10000; i++) { + testLong17_Long256(rl, al, bl, mask); + verifyLong17(rl, al, bl, mask); + } + } + @Run(test = {"testLong17_Long512"}, mode = RunMode.STANDALONE) + public void kernel_testLong17_Long512() { + for (int i = 0; i < 10000; i++) { + testLong17_Long512(rl, al, bl, mask); + verifyLong17(rl, al, bl, mask); + } + } + public TestMaskedMacroLogicVector() { br = new boolean[SIZE]; ba = fillBooleanRandom((()-> new boolean[SIZE])); From 93fa770778e99e8eef02f818d64decb6ef56d103 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Fri, 21 Aug 2026 08:30:24 +0000 Subject: [PATCH 017/223] 8390143: [lworld] PPC64 TemplateTable::getfield_or_static() with `may_not_rewrite` does not detect flattened field Reviewed-by: mdoerr, dbriemann --- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 8b9d3d7c4344..dfb59f071d34 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -2647,10 +2647,12 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr Rscratch = R11_scratch1; // used by load_field_cp_cache_entry // R12_scratch2 used by load_field_cp_cache_entry - static address field_branch_table[number_of_states], + static address field_rw_branch_table[number_of_states], + field_norw_branch_table[number_of_states], static_branch_table[number_of_states]; - address* branch_table = (is_static || rc == may_not_rewrite) ? static_branch_table : field_branch_table; + address* branch_table = is_static ? static_branch_table : + (rc == may_rewrite ? field_rw_branch_table : field_norw_branch_table); // Get field offset. resolve_cache_and_index_for_field(byte_no, Rcache, Rscratch); @@ -2698,14 +2700,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr #ifdef ASSERT __ bind(LFlagInvalid); __ stop("got invalid flag"); -#endif - if (!is_static && rc == may_not_rewrite) { - // We reuse the code from is_static. It's jumped to via the table above. - return; - } - -#ifdef ASSERT // __ bind(Lvtos); address pc_before_fence = __ pc(); __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). From bc15e5359b526bbe4504bfbd77f41aae062bcc1e Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 21 Aug 2026 09:01:18 +0000 Subject: [PATCH 018/223] 8390314: Linux: "assert(current_limit <= upper_bound) failed: invariant" build failure on incus (cgroups) Reviewed-by: shade, cnorrbin --- .../os/linux/cgroupV2Subsystem_linux.cpp | 3 +- .../SystemdMemoryExceedHostMemTest.java | 83 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/containers/systemd/SystemdMemoryExceedHostMemTest.java diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index edd80bb7427d..b69feab2cb4d 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -340,7 +340,8 @@ bool CgroupV2MemoryController::read_memory_limit_in_bytes(physical_memory_size_t } } } - result = limit; + // treat exceeding physical memory as unlimited + result = exceeds_physical_mem ? value_unlimited : limit; return true; } diff --git a/test/hotspot/jtreg/containers/systemd/SystemdMemoryExceedHostMemTest.java b/test/hotspot/jtreg/containers/systemd/SystemdMemoryExceedHostMemTest.java new file mode 100644 index 000000000000..358c52eb117f --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/SystemdMemoryExceedHostMemTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026 IBM Corporation. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.containers.systemd.SystemdRunOptions; +import jdk.test.lib.containers.systemd.SystemdTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + +/* + * @test + * @bug 8390314 + * @summary Verify no asserts are triggered in cgroup adjusting code + * when memory limit exceeds physical host memory. + * @requires systemd.support + * @library /test/lib + * @modules java.base/jdk.internal.platform + * @build HelloSystemd jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:whitebox.jar -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SystemdMemoryExceedHostMemTest + */ +public class SystemdMemoryExceedHostMemTest { + + private static final int MB = 1024 * 1024; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + private static final String TEST_SLICE_NAME = SystemdMemoryExceedHostMemTest.class.getSimpleName() + "HS"; + + public static void main(String[] args) throws Exception { + testMemExceedsPhysical(); + } + + private static void testMemExceedsPhysical() throws Exception { + SystemdRunOptions opts = SystemdTestUtils.newOpts("HelloSystemd"); + int expectedMemLimit = 1024; + // 1 GB memory, the lower hierarchy has a value exceeding physical memory + opts.memoryLimit(String.format("%dM", expectedMemLimit)); + // Set the memory limit of a slice stricly larger than the host + // max memory + String exceedingHostMem = getHostMaxMemory() + "0"; // add a zero + opts.sliceDMemoryLimit(exceedingHostMem); + opts.cpuLimit("100%"); // 1 core + opts.sliceName(TEST_SLICE_NAME); + + OutputAnalyzer out = SystemdTestUtils.buildAndRunSystemdJava(opts); + // On affected systems this asserts in fastdebug + out.shouldHaveExitValue(0) + .shouldContain("Hello Systemd"); + try { + out.shouldContain(String.format("Memory Limit is: %d", (expectedMemLimit * MB))); + } catch (RuntimeException e) { + // memory delegation needs to be enabled when run as user on cg v2 + if (SystemdTestUtils.RUN_AS_USER) { + String hint = "When run as user on cg v2 memory delegation needs to be configured!"; + throw new SkippedException(hint); + } + throw e; + } + } + + private static String getHostMaxMemory() { + return Long.valueOf(wb.hostPhysicalMemory()).toString(); + } +} From 544c2b6a5ad5c5671218f1c5dcf2754ac3816114 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 21 Aug 2026 09:31:58 +0000 Subject: [PATCH 019/223] 8328078: C2 compilation bailout with "too many D-U pinch points" Co-authored-by: Daniel Skantz Reviewed-by: chagedorn, rcastanedalo --- src/hotspot/share/opto/output.cpp | 1 + .../compiler/c2/TestDUPinchPointReuse.java | 61 +++++++++++++++++++ .../stringopts/TestStackedConcatsMany.java | 14 ++--- .../TestStackedConcatsManyUTF16Overflow.java | 6 +- 4 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestDUPinchPointReuse.java diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 45a6f206d703..460c0c466779 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -2889,6 +2889,7 @@ void Scheduling::anti_do_def( Block *b, Node *def, OptoReg::Name def_reg, int is // Yes, found a use/kill pinch-point pinch->set_req(0,nullptr); // pinch->replace_by(kill); // Move anti-dep edges up + _pinch_free_list.push(pinch); pinch = kill; _reg_node.map(def_reg,pinch); return; diff --git a/test/hotspot/jtreg/compiler/c2/TestDUPinchPointReuse.java b/test/hotspot/jtreg/compiler/c2/TestDUPinchPointReuse.java new file mode 100644 index 000000000000..51445fa32d64 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestDUPinchPointReuse.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8328078 + * @summary Test that block scheduling reuses detached D-U pinch-point nodes + * @requires vm.compiler2.enabled + * @library /test/lib + * @run main ${test.main.class} + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions + * -XX:+AbortVMOnCompilationFailure -XX:+OptoScheduling + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + */ + +package compiler.c2; + +import jdk.test.lib.Asserts; + +public class TestDUPinchPointReuse { + private static String append(String s) { + return new StringBuilder().append(s).append(s).append(s).append(s).append(s).toString(); + } + + private static String test() { + String s = "x"; + s = append(s); + s = append(s); + s = append(s); + s = append(s); + s = append(s); + s = append(s); + return s; + } + + public static void main(String[] args) { + new StringBuilder(); + Asserts.assertEQ(test().length(), 15625); + } +} diff --git a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java index dbc6e4955942..42a759d9f881 100644 --- a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java +++ b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,19 +23,17 @@ /* * @test - * @bug 8362394 + * @bug 8328078 8362394 * @summary Test that repeated stacked string concatenations do not * consume too many compilation resources. * @requires vm.compiler2.enabled * @library /test/lib / - * @run main/othervm -XX:-OptoScheduling compiler.stringopts.TestStackedConcatsMany - * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:-OptoScheduling - * -XX:CompileOnly=compiler.stringopts.TestStackedConcatsMany::f - * compiler.stringopts.TestStackedConcatsMany + * @run main ${test.main.class} + * @run main/othervm -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=${test.main.class}::f + * ${test.main.class} */ -// The test uses -XX:-OptoScheduling to avoid the assert "too many D-U pinch points" on aarch64 (JDK-8328078). - package compiler.stringopts; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsManyUTF16Overflow.java b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsManyUTF16Overflow.java index 1c9bdf153e8f..fc19276beb4d 100644 --- a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsManyUTF16Overflow.java +++ b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsManyUTF16Overflow.java @@ -27,15 +27,13 @@ * @summary Test that UTF-16 string concat overflow does not produce a negative size backing array * @requires vm.compiler2.enabled & os.maxMemory > 4G * @library /test/lib / - * @run main/othervm -Xmx4g -XX:-OptoScheduling ${test.main.class} + * @run main/othervm -Xmx4g ${test.main.class} * @run main/othervm -Xmx4g -Xint ${test.main.class} - * @run main/othervm -Xmx4g -XX:-TieredCompilation -Xcomp -XX:-OptoScheduling + * @run main/othervm -Xmx4g -XX:-TieredCompilation -Xcomp * -XX:CompileOnly=${test.main.class}::f * ${test.main.class} */ -// The test uses -XX:-OptoScheduling to avoid the assert "too many D-U pinch points" on aarch64 (JDK-8328078). - package compiler.stringopts; import jdk.test.lib.Asserts; From eb7d9a9b6149e539ca2d954552ce1ea2cb9e6923 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 21 Aug 2026 11:44:38 +0000 Subject: [PATCH 020/223] 8390386: [Linux] Systemd tests failing on systemd newer than 257 Reviewed-by: shade, roland --- .../jdk/test/lib/containers/systemd/SystemdTestUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java index 5a868b8cd2a7..724c6a5a535c 100644 --- a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java @@ -249,7 +249,7 @@ private static String getMemorySlice(SystemdRunOptions runOpts, String sliceName private static String getMemoryDSliceContent(SystemdRunOptions runOpts) { String format = "[Slice]\n" + basicMemoryContentFormat(); - return String.format(format, runOpts.sliceDMemoryLimit); + return String.format(format, runOpts.sliceDMemoryLimit, runOpts.sliceDMemoryLimit); } private static String getCPUDSliceContent(SystemdRunOptions runOpts) { @@ -268,13 +268,14 @@ private static String basicMemoryContentFormat() { return """ MemoryAccounting=true MemoryLimit=%s + MemoryMax=%s """; } private static String getMemorySliceContent(SystemdRunOptions runOpts) { String format = basicMemoryContentFormat(); - return String.format(format, runOpts.memoryLimit); + return String.format(format, runOpts.memoryLimit, runOpts.memoryLimit); } private static String getBasicSliceFormat() { From 6212c8075b4791e11c9c27c202e932fa7e0a88ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20B=C3=A1lek?= Date: Fri, 21 Aug 2026 13:13:57 +0000 Subject: [PATCH 021/223] 8390505: jlink is not thread safe when used via ToolProvider API Reviewed-by: alanb --- .../jdk/tools/jlink/internal/JlinkTask.java | 36 +++++++++++-------- .../tools/jlink/JLinkToolProviderTest.java | 33 ++++++++++++++++- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 45800be52725..356ba3de6234 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -89,7 +89,7 @@ public class JlinkTask { // jlink API ignores by default. Remove when signing is implemented. static final boolean IGNORE_SIGNING_DEFAULT = true; - private static final TaskHelper taskHelper + private final TaskHelper taskHelper = new TaskHelper(JLINK_BUNDLE); private static final Option[] recognizedOptions = { new Option(false, (task, opt, arg) -> { @@ -110,7 +110,7 @@ public class JlinkTask { task.options.limitMods.clear(); for (String mn : arg.split(",")) { if (mn.isEmpty()) { - throw taskHelper.newBadArgs("err.mods.must.be.specified", + throw task.taskHelper.newBadArgs("err.mods.must.be.specified", "--limit-modules"); } task.options.limitMods.add(mn); @@ -119,7 +119,7 @@ public class JlinkTask { new Option(true, (task, opt, arg) -> { for (String mn : arg.split(",")) { if (mn.isEmpty()) { - throw taskHelper.newBadArgs("err.mods.must.be.specified", + throw task.taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules"); } task.options.addMods.add(mn); @@ -139,18 +139,18 @@ public class JlinkTask { String[] values = arg.split("="); // check values if (values.length != 2 || values[0].isEmpty() || values[1].isEmpty()) { - throw taskHelper.newBadArgs("err.launcher.value.format", arg); + throw task.taskHelper.newBadArgs("err.launcher.value.format", arg); } else { String commandName = values[0]; String moduleAndMain = values[1]; int idx = moduleAndMain.indexOf("/"); if (idx != -1) { if (moduleAndMain.substring(0, idx).isEmpty()) { - throw taskHelper.newBadArgs("err.launcher.module.name.empty", arg); + throw task.taskHelper.newBadArgs("err.launcher.module.name.empty", arg); } if (moduleAndMain.substring(idx + 1).isEmpty()) { - throw taskHelper.newBadArgs("err.launcher.main.class.empty", arg); + throw task.taskHelper.newBadArgs("err.launcher.main.class.empty", arg); } } task.options.launchers.put(commandName, moduleAndMain); @@ -162,7 +162,7 @@ public class JlinkTask { } else if ("big".equals(arg)) { task.options.endian = ByteOrder.BIG_ENDIAN; } else { - throw taskHelper.newBadArgs("err.unknown.byte.order", arg); + throw task.taskHelper.newBadArgs("err.unknown.byte.order", arg); } }, "--endian"), new Option(false, (task, opt, arg) -> { @@ -174,7 +174,7 @@ public class JlinkTask { new Option(true, (task, opt, arg) -> { Path path = Paths.get(arg); if (Files.exists(path)) { - throw taskHelper.newBadArgs("err.dir.exists", path); + throw task.taskHelper.newBadArgs("err.dir.exists", path); } task.options.packagedModulesPath = path; }, true, "--keep-packaged-modules"), @@ -201,7 +201,7 @@ public class JlinkTask { private static final String PROGNAME = "jlink"; private final OptionsValues options = new OptionsValues(); - private static final OptionsHelper optionsHelper + private final OptionsHelper optionsHelper = taskHelper.newOptionsHelper(JlinkTask.class, recognizedOptions); private PrintWriter log; @@ -375,6 +375,7 @@ public static void createImage(JlinkConfiguration config, // First create the image provider try (ImageHelper imageProvider = createImageProvider(config, + new TaskHelper(JLINK_BUNDLE), null, IGNORE_SIGNING_DEFAULT, false, @@ -513,6 +514,7 @@ private void createImage(JlinkConfiguration config) throws Exception { // First create the image provider try (ImageHelper imageProvider = createImageProvider(config, + taskHelper, options.packagedModulesPath, options.ignoreSigning, options.bindServices, @@ -606,7 +608,7 @@ private static String getCurrentRuntimeVersion() { * @throws IllegalArgumentException If the `java.base` module reference `target` * is not compatible with this jlink. */ - private static void checkJavaBaseVersion(ModuleReference target) { + private void checkJavaBaseVersion(ModuleReference target) { String currentRelease = getCurrentRuntimeVersion(); String targetRelease = getReleaseInfo(target).orElseThrow(() -> new IllegalArgumentException( @@ -653,6 +655,7 @@ private static Path toPathLocation(ResolvedModule m) { private static ImageHelper createImageProvider(JlinkConfiguration config, + TaskHelper taskHelper, Path retainModulesPath, boolean ignoreSigning, boolean bindService, @@ -733,7 +736,7 @@ private static ImageHelper createImageProvider(JlinkConfiguration config, Map mods = cf.modules().stream() .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation)); // determine the target platform of the image being created - Platform targetPlatform = targetPlatform(cf, mods, config.linkFromRuntimeImage()); + Platform targetPlatform = targetPlatform(cf, taskHelper, mods, config.linkFromRuntimeImage()); // if the user specified any --endian, then it must match the target platform's native // endianness if (endian != null && endian != targetPlatform.arch().byteOrder()) { @@ -764,6 +767,7 @@ private static ImageHelper createImageProvider(JlinkConfiguration config, version, ignoreSigning, config, + taskHelper, log)) .collect(Collectors.toSet()); @@ -778,6 +782,7 @@ private static Archive newArchive(String module, Runtime.Version version, boolean ignoreSigning, JlinkConfiguration config, + TaskHelper taskHelper, PrintWriter log) { if (path.toString().endsWith(".jmod")) { return new JmodArchive(module, path); @@ -812,7 +817,7 @@ private static Archive newArchive(String module, // directory. I.e. Files.isDirectory() would be true. Path modInfoPath = path.resolve("module-info.class"); if (Files.isRegularFile(modInfoPath)) { - return new DirArchive(path, findModuleName(modInfoPath)); + return new DirArchive(path, findModuleName(taskHelper, modInfoPath)); } else { throw new IllegalArgumentException( taskHelper.getMessage("err.not.a.module.directory", path)); @@ -825,7 +830,7 @@ private static Archive newArchive(String module, } } - private static String findModuleName(Path modInfoPath) { + private static String findModuleName(TaskHelper taskHelper, Path modInfoPath) { try (BufferedInputStream bis = new BufferedInputStream( Files.newInputStream(modInfoPath))) { return ModuleDescriptor.read(bis).name(); @@ -836,6 +841,7 @@ private static String findModuleName(Path modInfoPath) { } private static Platform targetPlatform(Configuration cf, + TaskHelper taskHelper, Map modsPaths, boolean runtimeImageLink) throws IOException { Path javaBasePath = modsPaths.get("java.base"); @@ -850,7 +856,7 @@ private static Platform targetPlatform(Configuration cf, // this is an attempt to build a cross-platform image. We now attempt to // find the target platform's arch and thus its endianness from the java.base // module's ModuleTarget attribute - String targetPlatformVal = readJavaBaseTargetPlatform(cf); + String targetPlatformVal = readJavaBaseTargetPlatform(cf, taskHelper); try { return Platform.parsePlatform(targetPlatformVal); } catch (IllegalArgumentException iae) { @@ -879,7 +885,7 @@ private static boolean isJavaBaseFromDefaultModulePath(Path javaBasePath) throws // returns the targetPlatform value from the ModuleTarget attribute of the java.base module. // throws IOException if the targetPlatform cannot be determined. - private static String readJavaBaseTargetPlatform(Configuration cf) throws IOException { + private static String readJavaBaseTargetPlatform(Configuration cf, TaskHelper taskHelper) throws IOException { Optional javaBase = cf.findModule("java.base"); assert javaBase.isPresent() : "java.base module is missing"; ModuleReference ref = javaBase.get().reference(); diff --git a/test/jdk/tools/jlink/JLinkToolProviderTest.java b/test/jdk/tools/jlink/JLinkToolProviderTest.java index cb1f2f90c439..94959dcc8d80 100644 --- a/test/jdk/tools/jlink/JLinkToolProviderTest.java +++ b/test/jdk/tools/jlink/JLinkToolProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,12 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.Phaser; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.IntStream; import java.util.spi.ToolProvider; /* @@ -42,8 +48,33 @@ private static void checkJlinkOptions(String... options) { JLINK_TOOL.run(pw, pw, options); } + private static void checkConcurrentAccess(int count) throws Exception { + Phaser startBarrier = new Phaser(count); + + try (var executor = Executors.newFixedThreadPool(count)) { + List> futures = IntStream.range(0, count).mapToObj(idx -> executor.submit(() -> { + startBarrier.arriveAndAwaitAdvance(); + + StringWriter out = new StringWriter(); + StringWriter err = new StringWriter(); + int code = JLINK_TOOL.run(new PrintWriter(out), new PrintWriter(err), + "--add-modules", "java.base", + "--output", Path.of(".").resolve("image-" + idx).toString()); + return code + ":" + out.toString().trim() + ":" + err.toString().trim(); + })).toList(); + + for (Future future : futures) { + String result = future.get(); + if (!"0::".equals(result)) { + throw new AssertionError(result); + } + } + } + } + public static void main(String[] args) throws Exception { checkJlinkOptions("--help"); checkJlinkOptions("--list-plugins"); + checkConcurrentAccess(Math.max(2, Runtime.getRuntime().availableProcessors() / 4)); } } From 8ffe6c9d0ff5102dd72ba14bebba36e20d4513a3 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 21 Aug 2026 13:16:41 +0000 Subject: [PATCH 022/223] 8390288: The javax/swing/JTable/7124218/SelectEditTableCell.java fails on OL9.5 Reviewed-by: psadhukhan, jdv --- .../JTable/7124218/SelectEditTableCell.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/jdk/javax/swing/JTable/7124218/SelectEditTableCell.java b/test/jdk/javax/swing/JTable/7124218/SelectEditTableCell.java index 455c29c4696b..e319dd4fbb48 100644 --- a/test/jdk/javax/swing/JTable/7124218/SelectEditTableCell.java +++ b/test/jdk/javax/swing/JTable/7124218/SelectEditTableCell.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,10 @@ * @key headful * @bug 7124218 * @summary verifies different behaviour of SPACE and ENTER in JTable - * @library ../../regtesthelpers - * @build Util * @run main SelectEditTableCell */ import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; @@ -99,13 +98,16 @@ public void run() { } private static void runTestCase() throws Exception { - Point centerPoint; - centerPoint = Util.getCenterPoint(table); - LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); + Rectangle cellRect = table.getCellRect(0, 0, true); + Point centerPoint = new Point(cellRect.x + cellRect.width / 2,cellRect.y + cellRect.height / 2); + SwingUtilities.convertPointToScreen(centerPoint, table); + robot.mouseMove(centerPoint.x, centerPoint.y); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); + robot.delay(500); + SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { @@ -120,7 +122,7 @@ public void run() { }); int fetchKeyCode; - keyTap(fetchKeyCode = isMac(lookAndFeel) + keyTap(fetchKeyCode = isMac(UIManager.getLookAndFeel()) ? KeyEvent.VK_ENTER : KeyEvent.VK_SPACE); final int keyCode = fetchKeyCode; robot.waitForIdle(); From afc87f49795ed838d91d979fbef39c4530da10d5 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 21 Aug 2026 13:19:06 +0000 Subject: [PATCH 023/223] 8390545: java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java fails on OL9 Reviewed-by: psadhukhan, jdv --- .../jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java index 003977e233ad..93346d997c51 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java @@ -58,7 +58,6 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { {testEmbeddedFrame = true;} private boolean lwClicked = false; - private Point loc; private JPopupMenu popup; private JFrame frame=null; @@ -86,11 +85,12 @@ public void actionPerformed(ActionEvent event) { } propagateAWTControls(frame); frame.setVisible(true); - loc = frame.getContentPane().getLocationOnScreen(); } @Override protected boolean performTest() { + Point loc = frame.getContentPane().getLocationOnScreen(); + // run robot Robot robot = Util.createRobot(); robot.setAutoDelay(ROBOT_DELAY); From 7cb780a3d71f004830e377badfdab8861b6183be Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 21 Aug 2026 14:02:02 +0000 Subject: [PATCH 024/223] 8381223: Improve Java ML-DSA Performance Reviewed-by: semery, weijun --- .../classes/sun/security/provider/ML_DSA.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index e1b418174350..61fa63ff54ee 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -57,14 +57,15 @@ public class ML_DSA { private final int T0_COEFF_SIZE = 13; private static final int MONT_R_BITS = 32; - private static final long MONT_R = 4294967296L; // 1 << MONT_R_BITS private static final int MONT_Q = 8380417; - private static final int MONT_R_SQUARE_MOD_Q = 2365951; private static final int MONT_Q_INV_MOD_R = 58728449; private static final int MONT_R_MOD_Q = 4193792; // toMont((ML_DSA_N)^-1 (mod ML_DSA_Q)) private static final int MONT_DIM_INVERSE = 16382; + // ceil(2^63 / ML_DSA_Q), used with Math.multiplyHigh for Barrett reduction + private static final long BARRETT_MULTIPLIER = 1100586287873L; + // Zeta values for NTT with montgomery factor precomputed private static final int[] MONT_ZETAS_FOR_NTT = new int[]{ 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347, @@ -743,7 +744,7 @@ public boolean verifyInternal(byte[] pkBytes, byte[] message, byte[] sigBytes) int[][] aHatZ = integerMatrixAlloc(mlDsa_k, ML_DSA_N); matrixVectorPointwiseMultiply(aHatZ, aHat, sig.response()); - int[][] t1Hat = vectorConstMul(1 << ML_DSA_D, pk.t1()); + int[][] t1Hat = vectorConstMul(pk.t1()); mlDsaVectorNtt(t1Hat); int[][] ct1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); @@ -1439,7 +1440,9 @@ public static void mlDsaNttMultiply(int[] product, int[] coeffs1, int[] coeffs2) implDilithiumNttMult(product, coeffs1, coeffs2); } - + // Computes the pointwise product of two ordinary NTT-domain polynomials. + // The Java fallback uses Barrett reduction. Intrinsic implementations may use + // Montgomery multiplication internally, but produce the same result modulo q. @IntrinsicCandidate static int implDilithiumNttMult(int[] product, int[] coeffs1, int[] coeffs2) { implDilithiumNttMultJava(product, coeffs1, coeffs2); @@ -1448,7 +1451,9 @@ static int implDilithiumNttMult(int[] product, int[] coeffs1, int[] coeffs2) { static void implDilithiumNttMultJava(int[] product, int[] coeffs1, int[] coeffs2) { for (int i = 0; i < ML_DSA_N; i++) { - product[i] = montMul(coeffs1[i], toMont(coeffs2[i])); + // Both input coefficients are in the ordinary NTT domain, therefore + // the product is in the same domain. + product[i] = barrettReduce((long) coeffs1[i] * coeffs2[i]); } } @@ -1533,14 +1538,16 @@ private void nttConstMultiply(int[][] res, int[] a, int[][] b) { } } - private int[][] vectorConstMul(int c, int[][] vec) { + // Multiplies t1 by 2^D. Since t1 < 2^10, the product is at most + // q - 1 and needs no reduction. + private int[][] vectorConstMul(int[][] vec) { int[][] res = integerMatrixAlloc(vec.length, vec[0].length); for (int i = 0; i < vec.length; i++) { for (int j = 0; j < vec[0].length; j++) { - res[i][j] = montMul(c, toMont(vec[i][j])); + res[i][j] = (1 << ML_DSA_D) * vec[i][j]; } } - return res; // -q < res[i][j] < q + return res; // 0 <= res[i][j] < q } // Adds two vectors of polynomials @@ -1617,8 +1624,14 @@ private static int montMul(int b, int c) { return (aHigh - (int) (((long)m * MONT_Q) >> MONT_R_BITS)); } - static int toMont(int a) { - return montMul(a, MONT_R_SQUARE_MOD_Q); + // Reduces a product of two NTT coefficients modulo ML_DSA_Q to its + // canonical representative. The product is bounded by ML_DSA_Q squared. + private static int barrettReduce(long product) { + long quotient = Math.multiplyHigh(product, BARRETT_MULTIPLIER) << 1; + long r = product - quotient * ML_DSA_Q; + r -= ML_DSA_Q & ~((r - ML_DSA_Q) >> 63); + r += (r >> 63) & ML_DSA_Q; + return (int) r; } // For multidimensional array initialization, manually allocating each entry is From c5c690a4093b58fea2b1cfb840be5447c21611df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Fri, 21 Aug 2026 14:06:54 +0000 Subject: [PATCH 025/223] 8389756: JFR: premises for exclusive access to previous epoch are insufficient Reviewed-by: egahlin, coleenp --- src/hotspot/share/jfr/jfrEvents.hpp | 2 +- .../checkpoint/jfrCheckpointManager.cpp | 33 ++++++++----- .../jfr/recorder/checkpoint/types/jfrType.cpp | 16 +++--- .../checkpoint/types/jfrTypeManager.cpp | 28 ++++++----- .../recorder/checkpoint/types/jfrTypeSet.cpp | 49 +++++++++++++++---- .../checkpoint/types/jfrTypeSetUtils.hpp | 22 ++++++--- .../types/traceid/jfrTraceIdEpoch.cpp | 1 + .../traceid/jfrTraceIdLoadBarrier.inline.hpp | 5 +- .../recorder/service/jfrRecorderService.cpp | 14 ++++-- .../jfr/recorder/storage/jfrEpochStorage.hpp | 10 +++- .../storage/jfrMemorySpace.inline.hpp | 8 ++- .../storage/jfrStorageUtils.inline.hpp | 6 +-- .../share/jfr/support/jfrKlassUnloading.cpp | 4 +- src/hotspot/share/oops/instanceKlass.cpp | 17 +++++-- src/hotspot/share/runtime/mutexLocker.cpp | 2 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + 16 files changed, 150 insertions(+), 68 deletions(-) diff --git a/src/hotspot/share/jfr/jfrEvents.hpp b/src/hotspot/share/jfr/jfrEvents.hpp index ba0d9f5b61e8..d4437f7d64a2 100644 --- a/src/hotspot/share/jfr/jfrEvents.hpp +++ b/src/hotspot/share/jfr/jfrEvents.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index c6c1b4cad600..c1eded10f92b 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutex.hpp" #include "runtime/safepoint.hpp" +#include "runtime/thread.inline.hpp" typedef JfrCheckpointManager::BufferPtr BufferPtr; typedef JfrCheckpointManager::ConstBufferPtr ConstBufferPtr; @@ -257,6 +258,7 @@ BufferPtr JfrCheckpointManager::acquire_virtual_thread_local(Thread* thread, siz BufferPtr JfrCheckpointManager::renew(ConstBufferPtr old, Thread* thread, size_t size, JfrCheckpointBufferKind kind /* JFR_THREADLOCAL */) { assert(old != nullptr, "invariant"); assert(old->acquired_by_self(), "invariant"); + assert(!old->retired(), "invariant"); if (kind == JFR_GLOBAL) { return lease_global(thread, instance()._global_mspace->in_previous_epoch_list(old), size); } @@ -493,9 +495,10 @@ class VirtualThreadLocalCheckpointWriteOp { }; typedef CheckpointWriteOp WriteOperation; +typedef ExclusiveOp ExclusiveWriteOperation; typedef MutexedWriteOp MutexedWriteOperation; typedef ReleaseWithExcisionOp ReleaseOperation; -typedef CompositeOperation WriteReleaseOperation; +typedef CompositeOperation WriteReleaseOperation; typedef VirtualThreadLocalCheckpointWriteOp VirtualThreadLocalCheckpointOperation; typedef MutexedWriteOp VirtualThreadLocalWriteOperation; @@ -510,11 +513,12 @@ void JfrCheckpointManager::shift_epoch() { size_t JfrCheckpointManager::write() { DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(JavaThread::current())); WriteOperation wo(chunkwriter()); - MutexedWriteOperation mwo(wo); - _thread_local_mspace->iterate(mwo, true); // previous epoch list + // Must take exclusive ownership before writing, because non-Java threads can still have active usage. + ExclusiveWriteOperation ewo(wo); + _thread_local_mspace->iterate(ewo, true); // previous epoch list assert(_global_mspace->free_list_is_empty(), "invariant"); ReleaseOperation ro(_global_mspace, _global_mspace->live_list(true)); // previous epoch list - WriteReleaseOperation wro(&mwo, &ro); + WriteReleaseOperation wro(&ewo, &ro); process_live_list(wro, _global_mspace, true); // previous epoch list // Do virtual thread local list last. Careful, the vtlco destructor writes to chunk. VirtualThreadLocalCheckpointOperation vtlco(chunkwriter()); @@ -524,19 +528,22 @@ size_t JfrCheckpointManager::write() { } typedef DiscardOp > DiscardOperation; -typedef CompositeOperation DiscardReleaseOperation; +typedef ExclusiveDiscardOp > ExclusiveDiscardOperation; +typedef CompositeOperation DiscardReleaseOperation; size_t JfrCheckpointManager::clear() { JfrTraceIdLoadBarrier::clear(); clear_type_set(); - DiscardOperation dop(mutexed); // mutexed discard mode - _thread_local_mspace->iterate(dop, true); // previous epoch list + // Must take exclusive ownership before discarding, because non-Java threads can still have active usage. + ExclusiveDiscardOperation edo(mutexed); + _thread_local_mspace->iterate(edo, true); // previous epoch list + DiscardOperation dop(mutexed); // already has exclusive ownership discard mode _virtual_thread_local_mspace->iterate(dop, true); // previous epoch list ReleaseOperation ro(_global_mspace, _global_mspace->live_list(true)); // previous epoch list - DiscardReleaseOperation dro(&dop, &ro); + DiscardReleaseOperation dro(&edo, &ro); assert(_global_mspace->free_list_is_empty(), "invariant"); process_live_list(dro, _global_mspace, true); // previous epoch list - return dop.elements(); + return edo.elements() + dop.elements(); } size_t JfrCheckpointManager::write_static_type_set(Thread* thread) { @@ -623,7 +630,11 @@ void JfrCheckpointManager::write_type_set() { void JfrCheckpointManager::on_unloading_classes() { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - JfrCheckpointWriter writer(Thread::current()); + Thread* const current = Thread::current(); + // Take the epoch shift lock to ensure no epoch shift + // occurs during artifact serialization (for concurrent GCs). + ConditionalMutexLocker lock(current, JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + JfrCheckpointWriter writer(current); JfrTypeSet::on_unloading_classes(&writer); JfrAddRefCountedBlob add_blob(writer, false /* move */, false /* reset */); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp index 17d945af65e6..ded5a42ea82d 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,18 +111,22 @@ void JfrCheckpointThreadClosure::do_thread(Thread* t) { _writer.write(false); // isVirtual } +static inline void invoke(JfrCheckpointThreadClosure& tc, Thread* t) { + assert(t != nullptr, "invariant"); + if (t->jfr_thread_local()->should_write()) { + tc.do_thread(t); + } +} + void JfrThreadConstantSet::serialize(JfrCheckpointWriter& writer) { JfrCheckpointThreadClosure tc(writer); JfrJavaThreadIterator javathreads; while (javathreads.has_next()) { - JavaThread* const jt = javathreads.next(); - if (jt->jfr_thread_local()->should_write()) { - tc.do_thread(jt); - } + invoke(tc, javathreads.next()); } JfrNonJavaThreadIterator nonjavathreads; while (nonjavathreads.has_next()) { - tc.do_thread(nonjavathreads.next()); + invoke(tc, nonjavathreads.next()); } } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp index 58d12f709809..ddbfebb15984 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" #include "runtime/javaThread.hpp" +#include "runtime/safepoint.hpp" #include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" #include "utilities/macros.hpp" @@ -59,6 +60,7 @@ class JfrSerializerRegistration : public JfrCHeapObj { } void on_rotation() const { + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); _serializer->on_rotation(); } @@ -160,11 +162,16 @@ Semaphore SerializerRegistrationGuard::_mutex_semaphore(1); typedef JfrLinkedList List; static List types; +template +static inline void iterate(Processor& p) { + SerializerRegistrationGuard guard; + types.iterate(p); +} + void JfrTypeManager::destroy() { SerializerRegistrationGuard guard; - JfrSerializerRegistration* registration; while (types.is_nonempty()) { - registration = types.remove(); + JfrSerializerRegistration* registration = types.remove(); assert(registration != nullptr, "invariant"); delete registration; } @@ -180,8 +187,9 @@ class InvokeOnRotation { }; void JfrTypeManager::on_rotation() { + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); InvokeOnRotation ior; - types.iterate(ior); + iterate(ior); } #ifdef ASSERT @@ -211,12 +219,13 @@ static bool register_static_type(JfrTypeId id, bool permit_cache, JfrSerializer* delete serializer; return false; } - assert(!types.in_list(registration), "invariant"); - DEBUG_ONLY(assert_not_registered_twice(id, types);) if (JfrRecorder::is_recording()) { - JfrCheckpointWriter writer(Thread::current(), true, STATICS); + JfrCheckpointWriter writer(Thread::current(), true, STATICS, JFR_THREADLOCAL); registration->invoke(writer); } + SerializerRegistrationGuard guard; + assert(!types.in_list(registration), "invariant"); + DEBUG_ONLY(assert_not_registered_twice(id, types);) types.add(registration); return true; } @@ -232,7 +241,6 @@ static bool load_thread_constants(TRAPS) { } bool JfrTypeManager::initialize() { - SerializerRegistrationGuard guard; register_static_type(TYPE_FLAGVALUEORIGIN, true, new FlagValueOriginConstant()); register_static_type(TYPE_INFLATECAUSE, true, new MonitorInflateCauseConstant()); register_static_type(TYPE_GCCAUSE, true, new GCCauseConstant()); @@ -256,7 +264,6 @@ bool JfrTypeManager::initialize() { // implementation for the static registration function exposed in the JfrSerializer api bool JfrSerializer::register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) { - SerializerRegistrationGuard guard; return register_static_type(id, permit_cache, serializer); } @@ -274,6 +281,5 @@ class InvokeSerializer { void JfrTypeManager::write_static_types(JfrCheckpointWriter& writer) { InvokeSerializer is(writer); - SerializerRegistrationGuard guard; - types.iterate(is); + iterate(is); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 3dd9ea41d3d6..3141c5ab1abe 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,8 @@ #include "oops/instanceKlass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" +#include "runtime/mutex.hpp" +#include "runtime/thread.inline.hpp" #include "utilities/accessFlags.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/stack.inline.hpp" @@ -87,7 +89,13 @@ static inline bool previous_epoch() { template static inline bool used(const T* ptr) { assert(ptr != nullptr, "invariant"); - return current_epoch() ? USED_THIS_EPOCH(ptr) : USED_PREVIOUS_EPOCH(ptr); + if (flushpoint()) { + return USED_THIS_EPOCH(ptr); + } + if (unloading()) { + return USED_THIS_EPOCH(ptr) || USED_PREVIOUS_EPOCH(ptr); + } + return USED_PREVIOUS_EPOCH(ptr); } template @@ -257,7 +265,7 @@ class ModuleFieldSelector { if (pkg == nullptr) { return nullptr; } - assert(current_epoch() ? IS_SERIALIZED(pkg) : true, "invariant"); + assert(IS_SERIALIZED(pkg), "invariant"); return pkg->module(); } }; @@ -280,7 +288,7 @@ class ModuleCldFieldSelector { if (mod == nullptr) { return nullptr; } - assert(current_epoch() ? IS_SERIALIZED(mod) : true, "invariant"); + assert(IS_SERIALIZED(mod), "invariant"); return mod->loader_data(); } }; @@ -307,6 +315,16 @@ class SerializePredicate { } }; +#ifdef ASSERT +template +static bool test_is_previous_epoch_cleared_bit_set(const T* ptr) { + assert(ptr != nullptr, "invariant"); + const Thread* const current = Thread::current(); + assert(current != nullptr, "invariant"); + return !current->is_JfrRecorder_thread() || IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr); +} +#endif + template static void set_serialized(const T* ptr) { assert(ptr != nullptr, "invariant"); @@ -314,7 +332,7 @@ static void set_serialized(const T* ptr) { CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); assert(!IS_THIS_EPOCH_CLEARED_BIT_SET(ptr), "invariant"); } - assert(IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr), "invariant"); + assert(test_is_previous_epoch_cleared_bit_set(ptr), "invariant"); SET_SERIALIZED(ptr); assert(IS_SERIALIZED(ptr), "invariant"); } @@ -359,12 +377,12 @@ static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr kla return; } assert(used(klass), "invariant"); - assert(unloading() ? true : IS_NOT_SERIALIZED(klass), "invariant"); + assert(unloading() || IS_NOT_SERIALIZED(klass), "invariant"); set_serialized(klass); } static inline bool should_write_cld_klass(KlassPtr klass, bool leakp) { - return klass != nullptr && (leakp ? IS_LEAKP(klass) : unloading() ? true : IS_NOT_SERIALIZED(klass)); + return klass != nullptr && (leakp ? IS_LEAKP(klass) : unloading() || IS_NOT_SERIALIZED(klass)); } static void write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp, int& elements) { @@ -539,6 +557,7 @@ static void do_unloading_klass(Klass* klass) { assert(used(klass), "invariant"); } if (JfrKlassUnloading::on_unload(klass)) { + assert(used(klass), "invariant"); if (JfrTraceId::has_sticky_bit(klass)) { JfrMethodTracer::add_to_unloaded_set(klass); } @@ -996,6 +1015,15 @@ static void write_clds_on_clear() { /***** Methods *****/ +#ifdef ASSERT +static bool test_is_previous_epoch_method_cleared_bit_set(MethodPtr method) { + assert(method != nullptr, "invariant"); + const Thread* const current = Thread::current(); + assert(current != nullptr, "invariant"); + return !current->is_JfrRecorder_thread() || IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method); +} +#endif + template <> void set_serialized(MethodPtr method) { assert(method != nullptr, "invariant"); @@ -1003,9 +1031,9 @@ void set_serialized(MethodPtr method) { CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); assert(!IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); } - assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant"); + assert(test_is_previous_epoch_method_cleared_bit_set(method), "invariant"); + assert(unloading() || METHOD_IS_NOT_SERIALIZED(method), "invariant"); SET_METHOD_SERIALIZED(method); - assert(IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); assert(METHOD_IS_SERIALIZED(method), "invariant"); } @@ -1054,7 +1082,7 @@ class MethodIteratorHost { MethodIteratorHost(JfrCheckpointWriter* writer) : _method_cb(writer, unloading(), false), _klass_cb(writer, unloading(), false), - _method_flag_predicate(current_epoch()) {} + _method_flag_predicate(previous_epoch(), unloading()) {} bool operator()(KlassPtr klass) { if (klass->is_instance_klass()) { @@ -1320,6 +1348,7 @@ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_w } size_t JfrTypeSet::on_unloading_classes(JfrCheckpointWriter* writer) { + assert(!(UseShenandoahGC || UseZGC) || JfrEpochShift_lock->owned_by_self(), "invariant"); // JfrTraceIdEpoch::has_changed_tag_state_no_reset() is a load-acquire we issue to see side-effects (i.e. tags). // The JfrRecorderThread does this as part of normal processing, but with concurrent class unloading, which can // happen in arbitrary threads, we invoke it explicitly. diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index cc5ebb2be39f..3f11ea54924a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -1,5 +1,5 @@ -/* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + /* + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,14 +135,22 @@ class SymbolPredicate { template class MethodFlagPredicate { - bool _current_epoch; + const bool _previous_epoch; + const bool _class_unload; public: - MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {} + MethodFlagPredicate(bool previous_epoch, bool class_unload) : _previous_epoch(previous_epoch), _class_unload(class_unload) {} bool operator()(const Method* method) { - if (_current_epoch) { - return leakp ? METHOD_IS_LEAKP(method) : METHOD_FLAG_USED_THIS_EPOCH(method); + if (leakp) { + return METHOD_IS_LEAKP(method); } - return leakp ? METHOD_IS_LEAKP(method) : METHOD_FLAG_USED_PREVIOUS_EPOCH(method); + if (_previous_epoch) { + assert(!_class_unload, "invariant"); + return METHOD_FLAG_USED_PREVIOUS_EPOCH(method); + } + if (_class_unload) { + return METHOD_FLAG_USED_THIS_EPOCH(method) || METHOD_FLAG_USED_PREVIOUS_EPOCH(method); + } + return METHOD_FLAG_USED_THIS_EPOCH(method); } }; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp index bc7156adc4da..8a6e4f4c952f 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.cpp @@ -47,6 +47,7 @@ static constexpr const u2 epoch_generation_overflow = excluded_bit; void JfrTraceIdEpoch::shift_epoch() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); + assert(!(UseShenandoahGC || UseZGC) || JfrEpochShift_lock->owned_by_self(), "invariant"); _epoch_state = !_epoch_state; if (++_generation == epoch_generation_overflow) { _generation = 1; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp index c2b638401075..1eb876f4315b 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,12 +150,11 @@ inline traceid JfrTraceIdLoadBarrier::load(const ClassLoaderData* cld) { if (cld->has_class_mirror_holder()) { return 0; } - const traceid id = set_used_and_get(cld); const Klass* const class_loader_klass = cld->class_loader_klass(); if (class_loader_klass != nullptr) { load(class_loader_klass); } - return id; + return set_used_and_get(cld); } inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 6f8d44fb1a45..84c37e91df40 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -464,11 +464,14 @@ void JfrRecorderService::invoke_safepoint_clear() { void JfrRecorderService::safepoint_clear() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - _storage.clear(); _checkpoint_manager.notify_threads(true); - _chunkwriter.set_time_stamp(); JfrDeprecationManager::on_safepoint_clear(); JfrStackTraceRepository::clear(); + // Ensure that non-Java threads cannot perform tagging, enqueuing, + // or event writing that interleaves with the epoch shift. + ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + _storage.clear(); + _chunkwriter.set_time_stamp(); _checkpoint_manager.shift_epoch(); } @@ -576,10 +579,13 @@ void JfrRecorderService::safepoint_write() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); JfrStackTraceRepository::clear_leak_profiler(); _checkpoint_manager.on_rotation(); - _storage.write_at_safepoint(); - _chunkwriter.set_time_stamp(); JfrDeprecationManager::on_safepoint_write(); write_stacktrace(_stack_trace_repository, _chunkwriter, true); + // Ensure that non-Java threads cannot perform tagging, enqueuing, + // or event writing that interleaves with the epoch shift. + ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + _storage.write_at_safepoint(); + _chunkwriter.set_time_stamp(); _checkpoint_manager.shift_epoch(); } diff --git a/src/hotspot/share/jfr/recorder/storage/jfrEpochStorage.hpp b/src/hotspot/share/jfr/recorder/storage/jfrEpochStorage.hpp index 02f6a0ca7748..bb83c7fafbc7 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrEpochStorage.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrEpochStorage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ /* * Provides storage as a function of an epoch, with iteration capabilities for the current and previous epoch. * - * When iterating the previous epoch, where exclusive access to buffers is assumed, + * When iterating the previous epoch, where exclusive access to buffers is assumed (see disclaimer below), * all buffers will be reinitialized post-callback, with retired buffers reclaimed * and moved onto the free list and non-retired buffers left in-place. * @@ -47,6 +47,12 @@ * The design caters to use cases having multiple incremental iterations over the current epoch, * and a single iteration over the previous epoch. * + * DISCLAIMER: Exclusive access to the previous epoch is only guaranteed for uses that respect the safepoint protocol. + * This is because the JFR epoch evolves under a safepoint. If non-Java threads use the storage, + * observe that they do NOT respect when the epoch evolves. As such, they could still have active uses + * towards the previous epoch, although JavaThreads do not. In effect, this becomes another instance + * of concurrent access, as described for the current epoch. Be extra careful about who is using this kind of storage. + * * The JfrEpochStorage can be specialized by the following policies: * * NodeType the type of the Node to be managed by the JfrMemorySpace. diff --git a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp index 1b6273b78d2b..05fda370d12f 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -641,9 +641,13 @@ inline bool ReinitializeAllReleaseRetiredOp::process(typename template inline void assert_migration_state(const Node* old, const Node* new_node, size_t used, size_t requested) { assert(old != nullptr, "invariant"); - assert(new_node != nullptr, "invariant"); + assert(old->acquired_by_self(), "invariant"); + assert(!old->retired(), "invariant"); assert(old->pos() >= old->start(), "invariant"); assert(old->pos() + used <= old->end(), "invariant"); + assert(new_node != nullptr, "invariant"); + assert(new_node->acquired_by_self(), "invariant"); + assert(!new_node->retired(), "invariant"); assert(new_node->free_size() >= (used + requested), "invariant"); } #endif // ASSERT diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp index 5a7cb7e7a788..663ce3acd539 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,7 @@ inline bool ConcurrentWriteOp::process(typename Operation::Type* t) { const size_t unflushed_size = get_unflushed_size(top, t); assert((intptr_t)unflushed_size >= 0, "invariant"); if (unflushed_size == 0) { - if (is_retired) { - t->set_top(top); - } else { + if (!is_retired) { t->release_critical_section_top(top); } return true; diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp index d136eeab53ad..bf285c3f41e9 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,7 @@ bool JfrKlassUnloading::on_unload(const Klass* k) { ++event_klass_unloaded_count; } add_to_unloaded_klass_set(JfrTraceId::load_raw(k)); - return USED_THIS_EPOCH(k); + return USED_THIS_EPOCH(k) || USED_PREVIOUS_EPOCH(k); } static inline bool is_unloaded(const JfrCHeapTraceIdSet* set, const traceid& id) { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 65068c25d80a..e4bff1dbf70c 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3344,14 +3344,21 @@ void InstanceKlass::unload_class(InstanceKlass* ik) { log_info(class, unload)("unloading class %s " PTR_FORMAT, ik->external_name(), p2i(ik)); } - Events::log_class_unloading(Thread::current(), ik); + Thread* const current = Thread::current(); + Events::log_class_unloading(current, ik); #if INCLUDE_JFR assert(ik != nullptr, "invariant"); - EventClassUnload event; - event.set_unloadedClass(ik); - event.set_definingClassLoader(ik->class_loader_data()); - event.commit(); + // For concurrent unloading, we need the ik, the cld, and the event + // to end up in the correct JFR epoch, hence the acquisition of the + // epoch shift lock before the event.commit(). + if (EventClassUnload::is_enabled()) { + EventClassUnload event; + event.set_unloadedClass(ik); + event.set_definingClassLoader(ik->class_loader_data()); + ConditionalMutexLocker ml(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + event.commit(); + } #endif } diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index c9fa936f203b..291815647d7c 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -122,6 +122,7 @@ Mutex* JfrStacktrace_lock = nullptr; Monitor* JfrMsg_lock = nullptr; Mutex* JfrBuffer_lock = nullptr; Mutex* SuspendedThreadTask_lock = nullptr; +Mutex* JfrEpochShift_lock = nullptr; #endif Mutex* CodeHeapStateAnalytics_lock = nullptr; @@ -282,6 +283,7 @@ void mutex_init() { MUTEX_DEFN(JfrMsg_lock , PaddedMonitor, event); MUTEX_DEFN(JfrStacktrace_lock , PaddedMutex , event); MUTEX_DEFN(SuspendedThreadTask_lock , PaddedMutex , nosafepoint); + MUTEX_DEFN(JfrEpochShift_lock , PaddedMutex , service-5); // lets keep this just above event #endif MUTEX_DEFN(ContinuationRelativize_lock , PaddedMonitor, nosafepoint-3); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index ae9c5e8a1f1a..16fa8ebd5d03 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -140,6 +140,7 @@ extern Mutex* JfrStacktrace_lock; // used to guard access to the extern Monitor* JfrMsg_lock; // protects JFR messaging extern Mutex* JfrBuffer_lock; // protects JFR buffer operations extern Mutex* SuspendedThreadTask_lock; // used to guard SuspendedThreadTask::run +extern Mutex* JfrEpochShift_lock; // exclude non-java threads from interleaving with the JFR epoch shift #endif extern Mutex* Metaspace_lock; // protects Metaspace virtualspace and chunk expansions From 87e84f6ed34062e4a556399efd3bcea00d56bcd6 Mon Sep 17 00:00:00 2001 From: Ashay Rane Date: Fri, 21 Aug 2026 14:56:45 +0000 Subject: [PATCH 026/223] 8390353: AllocateHeapAt option can cause a HotSpot crash Reviewed-by: iklam, dholmes --- src/hotspot/os/windows/os_windows.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 06645f47eb2b..7cbfc2c821b4 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -127,6 +127,7 @@ static FILETIME process_creation_time; static FILETIME process_exit_time; static FILETIME process_user_time; static FILETIME process_kernel_time; +static HANDLE heap_file_handle = INVALID_HANDLE_VALUE; #if defined(_M_ARM64) #define __CPU__ aarch64 @@ -3244,6 +3245,20 @@ int os::create_file_for_heap(const char* dir) { warning("Problem opening file for heap (%s)", os::strerror(errno)); return -1; } + + guarantee(heap_file_handle == INVALID_HANDLE_VALUE, + "Heap backing file already exists"); + + HANDLE process = GetCurrentProcess(); + HANDLE file_handle = (HANDLE)_get_osfhandle(fd); + + if (!DuplicateHandle(process, file_handle, process, &heap_file_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + warning("Could not retain handle to heap backing file (error %lu)", GetLastError()); + ::close(fd); + return -1; + } + return fd; } From 8545f9166dbc1c1ca3d42d65f581e2a1a9e39f62 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 21 Aug 2026 15:07:07 +0000 Subject: [PATCH 027/223] 8324189: Test javax/sound/sampled/Clip/SetPositionHang.java timed out Reviewed-by: dcubed --- test/jdk/javax/sound/sampled/Clip/SetPositionHang.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java b/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java index 0805dfc45a03..d893c60a5c64 100644 --- a/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java +++ b/test/jdk/javax/sound/sampled/Clip/SetPositionHang.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ /** * @test * @bug 8266421 8269091 + * @key sound * @summary Tests that Clip.setFramePosition/setMicrosecondPosition do not hang. */ public final class SetPositionHang implements Runnable { From 46f0e2b4e766693aff4c7f460cd094d0f6e04c22 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Fri, 21 Aug 2026 16:02:28 +0000 Subject: [PATCH 028/223] 8388476: [Valhalla] C2 incorrectly eliminates store to flat array Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/compile.cpp | 8 ++- ...IncorrectlyEliminatedStoreToFlatArray.java | 71 +++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 14036abc9809..6ad48eda201c 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2307,15 +2307,17 @@ void Compile::adjust_flat_array_access_aliases(PhaseIterGVN& igvn) { } } -#ifdef ASSERT + int start_alias = num_alias_types(); // Start of new aliases for (uint i = 0; i < memnodes.size(); i++) { Node* m = memnodes.at(i); const TypePtr* adr_type = m->adr_type(); +#ifdef ASSERT m->as_Mem()->set_adr_type(adr_type); - } #endif // ASSERT + // This has the side effect of allocating new aliases for flat array accesses + get_alias_index(adr_type); + } - int start_alias = num_alias_types(); // Start of new aliases Node_Stack stack(0); #ifdef ASSERT VectorSet seen(Thread::current()->resource_area()); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java new file mode 100644 index 000000000000..8cb26b598a6b --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8388476 + * @summary [Valhalla] C2 incorrectly eliminates store to flat array + * + * @enablePreview + * @modules java.base/jdk.internal.value + * @run main/othervm -XX:-TieredCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions + * -XX:+IgnoreUnrecognizedVMOptions -XX:-UseArrayLoadStoreProfile + * -XX:CompileCommand=compileonly,${test.main.class}::test + * -XX:+AlwaysIncrementalInline ${test.main.class} + * @run main ${test.main.class} + */ + + +package compiler.valhalla.inlinetypes; +import jdk.internal.value.ValueClass; + +public class TestIncorrectlyEliminatedStoreToFlatArray { + static value class IntegerBox { + int value; + IntegerBox(int value) { this.value = value; } + public String toString() { return "value: " + value; } + } + + static Object test(Object obj, IntegerBox box) { + Object[] array = (Object[])obj; + try { + array[0] = null; + throw new NullPointerException("No NPE thrown"); + } catch (NullPointerException expected) { + array[0] = box; + } + return array[0]; + } + + public static void main(String[] args) { + IntegerBox[] array = (IntegerBox[])ValueClass.newNullRestrictedAtomicArray(IntegerBox.class, 1, new IntegerBox(1)); + + for (int i = 0; i < 50_000; i++) { + IntegerBox box = new IntegerBox(i); + Object res = test(array, box); + if (res != box) { + throw new AssertionError(res + " vs. " + box); + } + } + } +} From eef3c8a3a6dc52d1c49c49acc3f58d2e89f23e75 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 21 Aug 2026 16:07:51 +0000 Subject: [PATCH 029/223] 8390257: New test runtime/valhalla/inlinetypes/NPEInPreviewTest.java fails with -Xcomp Reviewed-by: matsaave, fparain, heidinga --- .../share/interpreter/bytecodeUtils.cpp | 18 +++++------------- src/hotspot/share/oops/constantPool.hpp | 6 ------ test/hotspot/jtreg/ProblemList.txt | 1 - .../valhalla/inlinetypes/NPEInPreviewTest.java | 10 +++++++++- test/jdk/ProblemList.txt | 2 -- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 469aa0d5dcc6..8dd1f2288e29 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -305,7 +305,7 @@ static char const* get_field_name(Method* method, int cp_index, Bytecodes::Code return name->as_C_string(); } -static bool is_null_restricted_field(Method* method, address code_base, int bci) { +static bool might_be_null_restricted_field(Method* method, address code_base, int bci) { ConstantPool* cp = method->constants(); int cp_index = Bytes::get_native_u2(code_base + bci + 1); ResolvedFieldEntry* field = cp->resolved_field_entry_at(cp_index); @@ -315,18 +315,10 @@ static bool is_null_restricted_field(Method* method, address code_base, int bci) if (is_resolved) { return field->is_null_free_inline_type(); } else { - // This is more expensive but rare. C1 might not have resolved the field - // in the interpreter first. - fieldDescriptor fd; - Klass* klass = cp->resolved_klass_ref_at(cp_index, bc); - assert (klass != nullptr, "must be resolved if we got an NPE here"); - - Symbol* name = cp->name_ref_at(cp_index, bc); - Symbol* sig = cp->signature_ref_at(cp_index, bc); - Klass* owner = InstanceKlass::cast(klass)->find_field(name, sig, false, &fd); - return owner != nullptr && fd.is_null_free_inline_type(); + // This is rare. The compiler might not have resolved the field or the klass + // in the interpreter first. Just say it might be null restricted because we don't know. + return true; } - return false; } static void print_local_var(outputStream *os, unsigned int bci, Method* method, int slot, bool is_parameter) { @@ -1205,7 +1197,7 @@ bool ExceptionMessageBuilder::print_NPE_cause(outputStream* os, int bci, int slo if (print_NPE_cause0(os, bci, slot, _max_cause_detail, false, " because \"")) { if (code == Bytecodes::_aastore) { os->print("\" is null or is a null-free array and there's an attempt to store null in it"); - } else if (code == Bytecodes::_putfield && is_null_restricted_field(_method, code_base, bci)) { + } else if (code == Bytecodes::_putfield && might_be_null_restricted_field(_method, code_base, bci)) { int cp_index = Bytes::get_native_u2(code_base + bci + 1); os->print("\" is null or \"%s\" is a null restricted field and there's an attempt to store null in it", get_field_name(_method, cp_index, code)); diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 8da04079eba4..824ec6409eba 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -580,12 +580,6 @@ class ConstantPool : public Metadata { return symbol_at(signature_index); } - // Returns a resolved klass or nullptr if not resolved. Does not try to resolve the class. - Klass* resolved_klass_ref_at(int which, Bytecodes::Code code) { - jint ref_index = klass_ref_index_at(which, code); - return resolved_klass_at(ref_index); - } - u2 klass_ref_index_at(int which, Bytecodes::Code code); u2 name_and_type_ref_index_at(int which, Bytecodes::Code code); diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 4ab802a270b8..059e2b3e083f 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -108,7 +108,6 @@ runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/NMT/VirtualAllocCommitMerge.java 8309698 linux-s390x runtime/Thread/TestAlwaysPreTouchStacks.java 8383372 macosx-aarch64 -runtime/valhalla/inlinetypes/NPEInPreviewTest.java 8390257 generic-all applications/jcstress/copy.java 8229852 linux-all diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java index e1f7bfe9796e..0488efed4a9c 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java @@ -29,6 +29,7 @@ * java.base/jdk.internal.vm.annotation * java.base/jdk.internal.misc * @library /test/lib + * @requires vm.flagless * @enablePreview * @compile -g NPEInPreviewTest.java * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowCodeDetailsInExceptionMessages NPEInPreviewTest interpreter @@ -100,6 +101,9 @@ static void testNullRestrictedFieldStoredInNullError() { static void testActualNullFieldError() { String expectedMessage = "Cannot assign field \"nullVal\" because \"self\" is null"; + // In C1 Xcomp mode, the field or klass isn't resolved, so no idea which this is. + String c1ExpectedMessage = "Cannot assign field \"nullVal\" because \"self\" is null or \"nullVal\" is a null " + + "restricted field and there's an attempt to store null in it"; try { NPEInPreviewTest self = null; @@ -107,7 +111,11 @@ static void testActualNullFieldError() { } catch (NullPointerException npe) { String message = npe.getMessage(); System.out.println("*** " + message); - Asserts.assertEquals(expectedMessage, message); + if (c1Mode) { + Asserts.assertEquals(c1ExpectedMessage, message); + } else { + Asserts.assertEquals(expectedMessage, message); + } } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1896f0231d39..16d23f73b38d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -570,8 +570,6 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_valhalla -valhalla/valuetypes/NullRestrictedTest.java 8390260 generic-all - ############################################################################ # core_tools From c52c07696a35c312e07b4d34b0b7565d6156815e Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 21 Aug 2026 17:12:39 +0000 Subject: [PATCH 030/223] 8390309: Remove deprecated comment() method from nsk.share.Log Reviewed-by: dholmes, cjplummer --- .../nsk/jdi/ReferenceType/equals/equals002.java | 14 +------------- .../failedToInitialize/failedtoinit002.java | 14 +------------- .../nsk/jdi/ReferenceType/fields/fields003.java | 14 +------------- .../jdi/ReferenceType/hashCode/hashcode002.java | 14 +------------- .../ReferenceType/isAbstract/isabstract002.java | 14 +------------- .../ReferenceType/isInitialized/isinit002.java | 14 +------------- .../ReferenceType/isPrepared/isprepared002.java | 14 +------------- .../ReferenceType/isVerified/isverified002.java | 14 +------------- .../jdi/ReferenceType/methods/methods003.java | 14 +------------- .../methodsByName_ss/methbyname_ss003.java | 14 +------------- .../nsk/jdi/ReferenceType/name/name002.java | 14 +------------- .../ReferenceType/sourceName/sourcename002.java | 14 +------------- .../ReferenceType/sourceName/sourcename003.java | 10 +--------- test/hotspot/jtreg/vmTestbase/nsk/share/Log.java | 16 +--------------- 14 files changed, 14 insertions(+), 180 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java index bcfcac4f8d0d..0686d73e69c7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class equals002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "equals002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> equals002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> equals002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> equals002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> equals002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.equals() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> equals002: checked class has been unloaded realy: " + checked_class); } else { - print_log_without_verbose - ("--> equals002: check that checked class has been unloaded realy..."); print_log_anyway ("--> equals002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java index 515e7f0140ef..f093fffe5032 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,6 @@ public class failedtoinit002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "failedtoinit002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -82,10 +80,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -151,8 +145,6 @@ private int runThis (String argv[], PrintStream out) { ("--> failedtoinit002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> failedtoinit002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> failedtoinit002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -172,8 +164,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> failedtoinit002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.failedToInitialize() method can NOT be checked!"); break; @@ -194,8 +184,6 @@ private int runThis (String argv[], PrintStream out) { ("--> failedtoinit002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> failedtoinit002: check that checked class has been unloaded really..."); print_log_anyway ("--> failedtoinit002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java index 03e9399f47e1..dee295d20f27 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,6 @@ public class fields003 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "fields003b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -82,10 +80,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -151,8 +145,6 @@ private int runThis (String argv[], PrintStream out) { ("--> fields003: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> fields003: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> fields003: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -172,8 +164,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> fields003: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.fields() method can NOT be checked!"); break; @@ -194,8 +184,6 @@ private int runThis (String argv[], PrintStream out) { ("--> fields003: checked class has been unloaded realy: " + checked_class); } else { - print_log_without_verbose - ("--> fields003: check that checked class has been unloaded realy..."); print_log_anyway ("--> fields003: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java index b3df10164766..edca601544b9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class hashcode002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "hashcode002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> hashcode002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> hashcode002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> hashcode002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> hashcode002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.hashCode() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> hashcode002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> hashcode002: check that checked class has been unloaded really..."); print_log_anyway ("--> hashcode002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java index 5d504d878e12..000054b284cc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,6 @@ public class isabstract002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "isabstract002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -82,10 +80,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -151,8 +145,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isabstract002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> isabstract002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> isabstract002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -172,8 +164,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> isabstract002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.isAbstract() method can NOT be checked!"); break; @@ -194,8 +184,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isabstract002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> isabstract002: check that checked class has been unloaded really..."); print_log_anyway ("--> isabstract002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java index 1675eb444c0d..c95a3703e970 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,6 @@ public class isinit002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "isinit002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -82,10 +80,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -151,8 +145,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isinit002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> isinit002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> isinit002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -172,8 +164,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> isinit002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.isInitialized() method can NOT be checked!"); break; @@ -194,8 +184,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isinit002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> isinit002: check that checked class has been unloaded really..."); print_log_anyway ("--> isinit002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java index e3680b64ab91..4bd57d907910 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class isprepared002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "isprepared002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isprepared002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> isprepared002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> isprepared002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> isprepared002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.isPrepared() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isprepared002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> isprepared002: check that checked class has been unloaded really..."); print_log_anyway ("--> isprepared002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java index 237f8e8f780d..2c89b8361f30 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,6 @@ public class isverified002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "isverified002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -84,10 +82,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -153,8 +147,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isverified002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> isverified002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> isverified002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -174,8 +166,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> isverified002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.isVerified() method can NOT be checked!"); break; @@ -196,8 +186,6 @@ private int runThis (String argv[], PrintStream out) { ("--> isverified002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> isverified002: check that checked class has been unloaded really..."); print_log_anyway ("--> isverified002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java index 7b37f8718d9d..073699ea9bfe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class methods003 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "methods003b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> methods003: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> methods003: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> methods003: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> methods003: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.methods() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> methods003: checked class has been unloaded realy: " + checked_class); } else { - print_log_without_verbose - ("--> methods003: check that checked class has been unloaded realy..."); print_log_anyway ("--> methods003: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java index 413d410037fa..3dbead204935 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,6 @@ public class methbyname_ss003 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "methbyname_ss003b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -84,10 +82,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -153,8 +147,6 @@ private int runThis (String argv[], PrintStream out) { ("--> methbyname_ss003: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> methbyname_ss003: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> methbyname_ss003: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -174,8 +166,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> methbyname_ss003: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.methodsByName_ss() method can NOT be checked!"); break; @@ -196,8 +186,6 @@ private int runThis (String argv[], PrintStream out) { ("--> methbyname_ss003: checked class has been unloaded realy: " + checked_class); } else { - print_log_without_verbose - ("--> methbyname_ss003: check that checked class has been unloaded realy..."); print_log_anyway ("--> methbyname_ss003: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java index d9af04da19b6..a59821d1c148 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class name002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "name002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> name002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> name002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> name002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> name002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.name() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> name002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> name002: check that checked class has been unloaded really..."); print_log_anyway ("--> name002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java index df523a5a5595..0db90110fbe3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,6 @@ public class sourcename002 { /** Debugee's class for check **/ private final static String checked_class = package_prefix + "sourcename002b"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -83,10 +81,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -152,8 +146,6 @@ private int runThis (String argv[], PrintStream out) { ("--> sourcename002: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> sourcename002: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> sourcename002: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; @@ -173,8 +165,6 @@ private int runThis (String argv[], PrintStream out) { if ( debugee_signal.equals("not_unloaded")) { print_log_anyway ("--> sourcename002: debugee's \"not_unloaded\" signal recieved!"); - print_log_without_verbose - ("--> checked class may be NOT unloaded!"); print_log_anyway ("--> ReferenceType.sourceName() method can NOT be checked!"); break; @@ -195,8 +185,6 @@ private int runThis (String argv[], PrintStream out) { ("--> sourcename002: checked class has been unloaded really: " + checked_class); } else { - print_log_without_verbose - ("--> sourcename002: check that checked class has been unloaded really..."); print_log_anyway ("--> sourcename002: checked class FOUND: " + checked_class + " => it has NOT been unloaded!"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java index c4163f123b4e..bd547529ec65 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,6 @@ public class sourcename003 { /** Debugee's class for check **/ private final static String checked_class = thisClassName + "[]"; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -84,10 +82,6 @@ private static void print_log_on_verbose(String message) { test_log_handler.display(message); } - private static void print_log_without_verbose(String message) { - test_log_handler.comment(message); - } - private static void print_log_anyway(String message) { test_log_handler.println(message); } @@ -136,8 +130,6 @@ private int runThis (String argv[], PrintStream out) { ("--> sourcename003: getting ReferenceType object for loaded checked class..."); ReferenceType refType = debugee.classByName(checked_class); if (refType == null) { - print_log_without_verbose - ("--> sourcename003: getting ReferenceType object for loaded checked class..."); print_log_anyway("##> sourcename003: FAILED: Could NOT FIND checked class: " + checked_class); class_not_found_error = true; break; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index 24711527606f..2e038291759c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.util.HashSet; import java.util.Vector; - /** * This class helps to print test-execution trace messages. *

@@ -211,19 +210,6 @@ public synchronized void println(String message) { doPrint(message); } - /** - * Print message to the assigned output stream, - * if log mode is non-verbose. - * - * @deprecated Test ought to be quiet if log mode is non-verbose - * and there is no errors found by the test. Methods - * display() and complain() - * are enough for testing purposes. - */ - @Deprecated - public synchronized void comment(String message) { - } - /** * Print trace message to the assigned output stream, * only if specified level is less or equal for the From 48490638d9d60e41551b2ac7d2846ba90a9b6908 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 21 Aug 2026 17:18:24 +0000 Subject: [PATCH 031/223] 8359208: Remove runtime/signal/TestSigstop.java since it is always skipped Reviewed-by: dholmes, shade, epavlova --- .../jtreg/runtime/signal/TestSigstop.java | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/signal/TestSigstop.java diff --git a/test/hotspot/jtreg/runtime/signal/TestSigstop.java b/test/hotspot/jtreg/runtime/signal/TestSigstop.java deleted file mode 100644 index 24acfd2c8dab..000000000000 --- a/test/hotspot/jtreg/runtime/signal/TestSigstop.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @requires os.family != "windows" & os.family != "aix" - * - * @summary converted from VM testbase runtime/signal/sigstop01. - * VM testbase keywords: [signal, runtime, linux, macosx] - * - * @library /test/lib - * @run main/native SigTestDriver SIGSTOP - */ - From 5ad2eb84b52c977c52399e110947b982142203c6 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 21 Aug 2026 17:36:02 +0000 Subject: [PATCH 032/223] 8389110: java/nio/file/FileStore/Basic.java testEnumerateFileStores fails in container: FileStores should be unique Reviewed-by: alanb, epavlova --- test/lib/jdk/test/lib/util/FileUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/util/FileUtils.java b/test/lib/jdk/test/lib/util/FileUtils.java index b5b49350389b..585d156999c1 100644 --- a/test/lib/jdk/test/lib/util/FileUtils.java +++ b/test/lib/jdk/test/lib/util/FileUtils.java @@ -263,7 +263,7 @@ public static boolean areFileSystemsAccessible() throws IOException { * File systems are considered to be accessible if this process completes * successfully before a given fixed duration has elapsed. * - * @implNote On Unix this executes the {@code df} command in a separate + * @implNote On Unix this executes the {@code df -a} command in a separate * process and on Windows always returns {@code true}. * * @return whether file systems appear to be accessible and duplicate-free @@ -274,7 +274,7 @@ public static boolean areMountPointsAccessibleAndUnique() { final AtomicBoolean areMountPointsOK = new AtomicBoolean(true); Thread thr = new Thread(() -> { try { - Process proc = new ProcessBuilder("df").start(); + Process proc = new ProcessBuilder("df", "-a").start(); BufferedReader reader = new BufferedReader (new InputStreamReader(proc.getInputStream())); // Skip the first line as it is the "df" output header. From 26842a3cdb0f2b5f92607546add3c145028aee73 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 21 Aug 2026 18:42:23 +0000 Subject: [PATCH 033/223] 8390391: [perf] InlineSmallCode should be increased for APX mode Reviewed-by: sviswanathan, drwhite --- src/hotspot/cpu/x86/vm_version_x86.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index a51faa0bea62..cfe0f91f0acd 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1077,6 +1077,14 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseAPX, false); } } +#if defined(COMPILER2) + if (UseAPX) { + // Increase InlineSmallCode by 10% + if (FLAG_IS_DEFAULT(InlineSmallCode)) { + FLAG_SET_DEFAULT(InlineSmallCode, InlineSmallCode * 1.10); + } + } +#endif CHECK_CPU_FEATURE(UseCLMUL, CLMUL, supports_clmul(), "CLMUL" MULTI_INST_WARNING_MSG); CHECK_CPU_FEATURE(UseAES, AES, supports_aes(), "AES" MULTI_INST_WARNING_MSG); From b5328c1cd7e5df98a0cd5930eee70d0024d89125 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 21 Aug 2026 19:35:27 +0000 Subject: [PATCH 034/223] 8389474: Class of inlined objects may not be AOT-initialized Reviewed-by: matsaave, coleenp, heidinga --- src/hotspot/share/cds/heapShared.cpp | 104 ++++++++++ src/hotspot/share/cds/heapShared.hpp | 3 + .../cds/appcds/aotCache/FlatArrayTest.java | 180 +++++++++++------- .../appcds/aotCache/FlattenedFieldTest.java | 174 +++++++++++++++++ .../test-classes/valueclasses/BytePair.java | 49 +++++ .../valueclasses/BytePairWrapper.java | 47 +++++ .../valueclasses/BytePairWrapperWrapper.java | 47 +++++ .../test-classes/valueclasses/CharPair.java | 49 +++++ .../valueclasses/IntegerWrapper.java | 43 +++++ .../test-classes/valueclasses/ShortPair.java | 49 +++++ .../valueclasses/ShortPairWrapper.java | 47 +++++ .../valueclasses/ValueClassHelper.java | 87 +++++++++ 12 files changed, 813 insertions(+), 66 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlattenedFieldTest.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePair.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapper.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapperWrapper.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/CharPair.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/IntegerWrapper.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPair.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPairWrapper.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ValueClassHelper.java diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 2fc23700d828..93d9061efb98 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -61,6 +61,7 @@ #include "memory/universe.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/fieldStreams.inline.hpp" +#include "oops/flatArrayOop.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopCast.inline.hpp" @@ -1742,6 +1743,107 @@ void HeapShared::init_box_classes(TRAPS) { } } +// Used by HeapShared::find_inline_classes(). +class HeapShared::InlineKlassFinder : public FieldClosure { + KlassSubGraphInfo* _subgraph_info; + InstanceKlass* _ik; + address _obj; +public: + // obj points to the "logical address" of: + // (a) a regular heap object, or + // (b) an element of a flattened array, or + // (c) a flattened field embedded inside a heap object. + // For (a), obj is the same as the address of the heap object. + // For (b) and (c), obj points to InlineKlass::cast(_ik)->payload_offset() bytes below + // the payload. + InlineKlassFinder(KlassSubGraphInfo* subgraph_info, InstanceKlass* ik, address obj) + : _subgraph_info(subgraph_info), _ik(ik), _obj(obj) { + precond(obj != nullptr); + precond(ik->has_inlined_fields()); + } + + // This function is called on every field of _ik. + void do_field(fieldDescriptor* fd) override { + if (fd->is_flat()) { + precond(fd->field_type() == T_OBJECT); + precond(_ik == fd->field_holder()); + + // The type of this flattened field + InlineKlass* vk = _ik->get_inline_type_field_klass(fd->index()); + + // The "logical address" of this flattened field + address field_addr = _obj + fd->offset() - vk->payload_offset(); + + if (fd->is_null_free_inline_type() || !vk->is_payload_marked_as_null(field_addr)) { + // Found a non-null flattened instance of vk. Let's record vk. + add_inline_class(_subgraph_info, vk); + if (vk->has_inlined_fields()) { + InlineKlassFinder finder(_subgraph_info, vk, field_addr); + finder.find(); + } + } + } + } + + void find() { + _ik->do_nonstatic_fields(this); + } +}; + +void HeapShared::add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* k) { + subgraph_info->add_subgraph_object_klass(k); + if (InstanceKlass::cast(k)->is_enum_subclass() + || (subgraph_info == _dump_time_special_subgraph)) { + AOTArtifactFinder::add_aot_inited_class(k); + } +} + +// Recursively scan for any InlineKlass K that has least one non-null flattened instance +// inside orig_obj. K should be recorded with add_inline_class(). +// +// Reason for doing this: +// +// value class Point { short x; short y; ... } +// value class Line { +// @NullRestricted Point p1; +// @NullRestricted Point p2; ... } +// +// Klasses of non-flattened instances are already recorded by HeapShared::archive_object(). +// +// If only a single instance of Line is archived, HeapShared::archive_object() would +// have never visited a (non-flattened) instance of Point, but we must store Point in +// AOT-initialized state. This function finds Point. +void HeapShared::find_inline_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj) { + Klass* klass = orig_obj->klass(); + + if (klass->is_flatArray_klass()) { + FlatArrayKlass* fak = FlatArrayKlass::cast(klass); + precond(orig_obj->is_flatArray()); + flatArrayOop fa = oop_cast(orig_obj); + InlineKlass* elem_k = fak->element_klass(); + bool added = false; + for (int i = 0; i < fa->length(); i++) { + if (fak->is_null_free_array_klass() || !fa->obj_at_is_null(i)) { + if (!added) { + add_inline_class(subgraph_info, elem_k); + } + if (elem_k->has_inlined_fields()) { + // "logical address" of the i-th array element. + address elem = static_cast

(fa->value_at_addr(i, fak->layout_helper())) - elem_k->payload_offset(); + InlineKlassFinder finder(subgraph_info, elem_k, elem); + finder.find(); + } + } + } + } else if (klass->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(klass); + if (ik->has_inlined_fields()) { + InlineKlassFinder finder(subgraph_info, ik, cast_from_oop
(orig_obj)); + finder.find(); + } + } +} + // (1) If orig_obj has not been archived yet, archive it. // (2) If orig_obj has not been seen yet (since start_recording_subgraph() was called), // trace all objects that are reachable from it, and make sure these objects are archived. @@ -1877,6 +1979,8 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap orig_obj->oop_iterate(&pusher); } + find_inline_classes(subgraph_info, orig_obj); + if (CDSConfig::is_dumping_aot_linked_classes()) { // The enum klasses are archived with aot-initialized mirror. // See AOTClassInitializer::can_archive_initialized_mirror(). diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index ba7ec626d909..993719909d81 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -365,11 +365,14 @@ class HeapShared: AllStatic { }; class OopFieldPusher; + class InlineKlassFinder; using PendingOopStack = GrowableArrayCHeap; static PendingOop _object_being_archived; static bool walk_one_object(PendingOopStack* stack, int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, oop referrer); + static void find_inline_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj); + static void add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* k); static void reset_archived_object_states(TRAPS); static void ensure_determinism(TRAPS); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlatArrayTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlatArrayTest.java index 94f2234f2a40..452ed24f25df 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlatArrayTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlatArrayTest.java @@ -27,22 +27,43 @@ * @requires vm.cds.supports.aot.class.linking * @requires vm.debug * @enablePreview - * @library /test/jdk/lib/testlibrary /test/lib + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes/ * @modules java.base/jdk.internal.value + * @modules java.base/jdk.internal.vm.annotation * @build FlatArrayTest * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * FlatArrayTestApp MyAOTInitedClass CharPair Wrapper + * FlatArrayTestApp + * MyAOTInitedClass + * valueclasses.BytePair + * valueclasses.BytePairWrapper + * valueclasses.BytePairWrapperWrapper + * valueclasses.CharPair + * valueclasses.IntegerWrapper + * valueclasses.ShortPair + * valueclasses.ShortPairWrapper + * valueclasses.ValueClassHelper * @run driver FlatArrayTest AOT --two-step-training */ import java.util.Arrays; import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; import jdk.test.lib.cds.CDSAppTester; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.StringArrayUtils; +// From ../test-classes/ +import valueclasses.BytePair; +import valueclasses.BytePairWrapper; +import valueclasses.BytePairWrapperWrapper; +import valueclasses.CharPair; +import valueclasses.ShortPair; +import valueclasses.ShortPairWrapper; +import valueclasses.IntegerWrapper; +import valueclasses.ValueClassHelper; + public class FlatArrayTest { static final String appJar = ClassFileInstaller.getJarPath("app.jar"); static final String mainClass = FlatArrayTestApp.class.getName(); @@ -89,8 +110,13 @@ public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception out.shouldContain("Y = 123"); } else if (runMode == RunMode.ASSEMBLY) { out.shouldMatch("klasses.* app .*MyAOTInitedClass .* inited"); + out.shouldMatch("klasses.* app .*BytePair .* inited"); + out.shouldMatch("klasses.* app .*BytePairWrapper .* inited"); + out.shouldMatch("klasses.* app .*BytePairWrapperWrapper .* inited"); out.shouldMatch("klasses.* app .*CharPair .* inited"); - out.shouldMatch("klasses.* app .*Wrapper .* inited"); + out.shouldMatch("klasses.* app .*IntegerWrapper .* inited"); + out.shouldMatch("klasses.* app .*ShortPair .* inited"); + out.shouldMatch("klasses.* app .*ShortPairWrapper .* inited"); } else if (runMode == RunMode.PRODUCTION) { out.shouldContain("Y = 45"); } @@ -98,47 +124,16 @@ public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception } } +// NOTE: this class is NOT aot-initialized. class FlatArrayTestApp { static int X = 45; + public static void main(String[] args) { X = 123; MyAOTInitedClass.test(args[0]); } } -value class CharPair implements Comparable { - char c0, c1; - - public String toString() { - return "(" + c0 + ", " + c1 + ")"; - } - - public int compareTo(CharPair o) { - return (c0 - o.c0) - (c1 - o.c1); - } - - public CharPair(char c0, char c1) { - this.c0 = c0; - this.c1 = c1; - } -} - -value class Wrapper implements Comparable { - Integer i; - - public String toString() { - return i.toString(); - } - - public int compareTo(Wrapper o) { - return i - o.i; - } - - Wrapper(int i) { - this.i = new Integer(i); - } -} - // This class is stored in the AOT cache in the initialized state. class MyAOTInitedClass { // Note that when MyAOTInitedClass is initialized in the assembly run, FlatArrayTestApp.main() @@ -147,15 +142,23 @@ class MyAOTInitedClass { static Integer[] intArray; static CharPair[] charPairArray; - static Wrapper[] wrapperArray; + static IntegerWrapper[] integerWrapperArray; + static ShortPairWrapper[] spwArray; + static BytePairWrapperWrapper[] bpwwArray; + // A non-flattened instance of CharPair. static CharPair charPair; - static Wrapper wrapper; + + // We don't have non-flattened instances of IntegerWrapper, but + // the IntegerWrapper class should still be AOT-initialized, as + // we can read a reference object of type IntegerWrapper from + // integerWrapperArray[0] + // + // The same is also true for BytePair, BytePairWrapper, BytePairWrapperWrapper, + // ShortPair, and ShortPairWrapper, for similar reasons. static { intArray = new Integer[3]; - intArray[0] = null; - System.out.println("TEST: " + (intArray[0] == null)); intArray[0] = new Integer(0); intArray[1] = new Integer(1); intArray[2] = new Integer(2); @@ -165,13 +168,22 @@ class MyAOTInitedClass { charPairArray[1] = new CharPair('c', 'd'); charPairArray[2] = new CharPair('e', 'f'); - wrapperArray = new Wrapper[3]; - wrapperArray[0] = new Wrapper(0); - wrapperArray[1] = new Wrapper(1); - wrapperArray[2] = new Wrapper(2); + integerWrapperArray = new IntegerWrapper[3]; + integerWrapperArray[0] = new IntegerWrapper(0); + integerWrapperArray[1] = new IntegerWrapper(1); + integerWrapperArray[2] = new IntegerWrapper(2); + + spwArray = new ShortPairWrapper[3]; + spwArray[0] = new ShortPairWrapper(0, 1); + spwArray[1] = new ShortPairWrapper(2, 3); + spwArray[2] = new ShortPairWrapper(4, 5); + + bpwwArray = new BytePairWrapperWrapper[3]; + bpwwArray[0] = new BytePairWrapperWrapper(0, 1); + bpwwArray[1] = new BytePairWrapperWrapper(2, 3); + bpwwArray[2] = new BytePairWrapperWrapper(4, 5); charPair = new CharPair('x', 'y'); - wrapper = new Wrapper(5); } static void test(String runMode) { @@ -188,36 +200,72 @@ static void test(String runMode) { throw new RuntimeException("CharPair array should be flat"); } - if (!ValueClass.isFlatArray(wrapperArray)) { - throw new RuntimeException("Wrapper array should be flat"); + if (!ValueClass.isFlatArray(integerWrapperArray)) { + throw new RuntimeException("IntegerWrapper array should be flat"); + } + + if (!ValueClass.isFlatArray(spwArray)) { + throw new RuntimeException("ShortPairWrapper array should be flat"); + } + + if (!ValueClass.isFlatArray(bpwwArray)) { + throw new RuntimeException("BytePairWrapperWrapper array should be flat"); } // Ensure archived arrays are restored properly - Integer[] runtimeIntArray = new Integer[3]; - runtimeIntArray[0] = new Integer(0); - runtimeIntArray[1] = new Integer(1); - runtimeIntArray[2] = new Integer(2); - - CharPair[] runtimeCharPairArray = new CharPair[3]; - runtimeCharPairArray[0] = new CharPair('a', 'b'); - runtimeCharPairArray[1] = new CharPair('c', 'd'); - runtimeCharPairArray[2] = new CharPair('e', 'f'); - - Wrapper[] runtimeWrapperArray = new Wrapper[3]; - runtimeWrapperArray[0] = new Wrapper(0); - runtimeWrapperArray[1] = new Wrapper(1); - runtimeWrapperArray[2] = new Wrapper(2); - - if (Arrays.compare(intArray, runtimeIntArray) != 0) { + Integer[] runtime_intArray = new Integer[3]; + runtime_intArray[0] = new Integer(0); + runtime_intArray[1] = new Integer(1); + runtime_intArray[2] = new Integer(2); + + CharPair[] runtime_charPairArray = new CharPair[3]; + runtime_charPairArray[0] = new CharPair('a', 'b'); + runtime_charPairArray[1] = new CharPair('c', 'd'); + runtime_charPairArray[2] = new CharPair('e', 'f'); + + IntegerWrapper[] runtime_integerWrapperArray = new IntegerWrapper[3]; + runtime_integerWrapperArray[0] = new IntegerWrapper(0); + runtime_integerWrapperArray[1] = new IntegerWrapper(1); + runtime_integerWrapperArray[2] = new IntegerWrapper(2); + + ShortPairWrapper[] runtime_spwArray = new ShortPairWrapper[3]; + runtime_spwArray[0] = new ShortPairWrapper(0, 1); + runtime_spwArray[1] = new ShortPairWrapper(2, 3); + runtime_spwArray[2] = new ShortPairWrapper(4, 5); + + BytePairWrapperWrapper[] runtime_bpwwArray = new BytePairWrapperWrapper[3]; + runtime_bpwwArray[0] = new BytePairWrapperWrapper(0, 1); + runtime_bpwwArray[1] = new BytePairWrapperWrapper(2, 3); + runtime_bpwwArray[2] = new BytePairWrapperWrapper(4, 5); + + if (Arrays.compare(intArray, runtime_intArray) != 0) { throw new RuntimeException("Integer array not restored correctly"); } - if (Arrays.compare(charPairArray, runtimeCharPairArray) != 0) { + if (Arrays.compare(charPairArray, runtime_charPairArray) != 0) { throw new RuntimeException("CharPair array not restored correctly"); } - if (Arrays.compare(wrapperArray, runtimeWrapperArray) != 0) { - throw new RuntimeException("Wrapper array not restored correctly"); + if (Arrays.compare(integerWrapperArray, runtime_integerWrapperArray) != 0) { + throw new RuntimeException("IntegerWrapper array not restored correctly"); + } + + if (Arrays.compare(spwArray, runtime_spwArray) != 0) { + throw new RuntimeException("ShortPairWrapper array not restored correctly"); + } + + if (Arrays.compare(bpwwArray, runtime_bpwwArray) != 0) { + throw new RuntimeException("BytePairWrapperWrapper array not restored correctly"); + } + + if (runMode.equals("PRODUCTION")) { + ValueClassHelper.assertAOTInited_BytePair(); + ValueClassHelper.assertAOTInited_BytePairWrapper(); + ValueClassHelper.assertAOTInited_BytePairWrapperWrapper(); + ValueClassHelper.assertAOTInited_CharPair(); + ValueClassHelper.assertAOTInited_IntegerWrapper(); + ValueClassHelper.assertAOTInited_ShortPair(); + ValueClassHelper.assertAOTInited_ShortPairWrapper(); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlattenedFieldTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlattenedFieldTest.java new file mode 100644 index 000000000000..471598c27ffd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/FlattenedFieldTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test Test AOT-cached flattened fields + * @requires vm.cds.supports.aot.class.linking + * @requires vm.debug + * @enablePreview + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes/ + * @modules java.base/jdk.internal.value + * @modules java.base/jdk.internal.vm.annotation + * @build FlattenedFieldTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * FlattenedFieldTestApp + * MyAOTInitedClass + * valueclasses.BytePair + * valueclasses.BytePairWrapper + * valueclasses.BytePairWrapperWrapper + * valueclasses.CharPair + * valueclasses.ShortPair + * valueclasses.ShortPairWrapper + * valueclasses.ValueClassHelper + * @run driver FlattenedFieldTest AOT --two-step-training + */ + +import java.util.Arrays; +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.StringArrayUtils; + +// From ../test-classes/ +import valueclasses.BytePair; +import valueclasses.BytePairWrapper; +import valueclasses.BytePairWrapperWrapper; +import valueclasses.CharPair; +import valueclasses.ShortPair; +import valueclasses.ShortPairWrapper; +import valueclasses.ValueClassHelper; + +public class FlattenedFieldTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = FlattenedFieldTestApp.class.getName(); + + public static void main(String[] args) throws Exception { + new Tester().run(args); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + String args[] = StringArrayUtils.concat("--enable-preview", + "--add-exports", + "java.base/jdk.internal.value=ALL-UNNAMED"); + if (runMode == RunMode.ASSEMBLY) { + args = StringArrayUtils.concat(args, + "-Xlog:aot+class=debug", + "-XX:AOTInitTestClass=MyAOTInitedClass"); + } + + return args; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + runMode.toString(), + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.TRAINING) { + out.shouldContain("Y = 123"); + } else if (runMode == RunMode.ASSEMBLY) { + out.shouldMatch("klasses.* app .*MyAOTInitedClass .* inited"); + out.shouldMatch("klasses.* app .*BytePair .* inited"); + out.shouldMatch("klasses.* app .*BytePairWrapper .* inited"); + out.shouldMatch("klasses.* app .*BytePairWrapperWrapper .* inited"); + out.shouldMatch("klasses.* app .*CharPair .* inited"); + out.shouldMatch("klasses.* app .*ShortPair .* inited"); + out.shouldMatch("klasses.* app .*ShortPairWrapper .* inited"); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldContain("Y = 45"); + } + } + } +} + +// NOTE: this class is NOT aot-initialized. +class FlattenedFieldTestApp { + static int X = 45; + + public static void main(String[] args) { + X = 123; + MyAOTInitedClass.test(args[0]); + } +} + +// This class is stored in the AOT cache in the initialized state. +class MyAOTInitedClass { + // Note that when MyAOTInitedClass is initialized in the assembly run, FlattenedFieldTestApp.main() + // is not executed, so the cached value of MyAOTInitedClass.Y will be 45; + static int Y = FlattenedFieldTestApp.X; + + static CharPair cp = new CharPair('a', 'b'); + static ShortPairWrapper spw = new ShortPairWrapper(2, 3); + static BytePairWrapperWrapper bpww = new BytePairWrapperWrapper(4, 5); + + static void test(String runMode) { + System.out.println("Y = " + Y); + if (runMode.equals("PRODUCTION") && Y != 45) { + throw new RuntimeException("MyAOTInitedClass must be AOT-inited"); + } + + CharPair runtime_cp = new CharPair('a', 'b'); + ShortPairWrapper runtime_spw = new ShortPairWrapper(2, 3); + BytePairWrapperWrapper runtime_bpww = new BytePairWrapperWrapper(4, 5); + + if (runtime_cp.compareTo(cp) != 0) { + throw new RuntimeException("CharPair not restored correctly"); + } + + if (runtime_spw.compareTo(spw) != 0) { + throw new RuntimeException("ShortPairWrapper not restored correctly"); + } + + if (runtime_bpww.compareTo(bpww) != 0) { + throw new RuntimeException("BytePairWrapperWrapper not not restored correctly"); + } + + if (runMode.equals("PRODUCTION")) { + ValueClassHelper.assertAOTInited_BytePair(); + ValueClassHelper.assertAOTInited_BytePairWrapper(); + ValueClassHelper.assertAOTInited_BytePairWrapperWrapper(); + ValueClassHelper.assertAOTInited_CharPair(); + ValueClassHelper.assertAOTInited_ShortPairWrapper(); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePair.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePair.java new file mode 100644 index 000000000000..b0ecef96851c --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePair.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +public value class BytePair implements Comparable { + static { + ValueClassHelper.clinit_called_for_BytePair = true; + } + byte b0, b1; + + public String toString() { + return "(" + b0 + ", " + b1 + ")"; + } + + public int compareTo(BytePair o) { + int n = b0 - o.b0; + if (n != n) { + return n; + } else { + return (b1 - o.b1); + } + } + + public BytePair(int b0, int b1) { + this.b0 = (byte)b0; + this.b1 = (byte)b1; + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapper.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapper.java new file mode 100644 index 000000000000..fdd342a56ba2 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +import jdk.internal.vm.annotation.NullRestricted; + +public value class BytePairWrapper implements Comparable { + static { + ValueClassHelper.clinit_called_for_BytePairWrapper = true; + } + @NullRestricted + BytePair bp; + + public String toString() { + return "Wrapping {" + bp.toString() + "}"; + } + + public int compareTo(BytePairWrapper other) { + return bp.compareTo(other.bp); + } + + public BytePairWrapper(int b0, int b1) { + bp = new BytePair(b0, b1); + super(); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapperWrapper.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapperWrapper.java new file mode 100644 index 000000000000..9769d7a72fcd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/BytePairWrapperWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +import jdk.internal.vm.annotation.NullRestricted; + +public value class BytePairWrapperWrapper implements Comparable { + static { + ValueClassHelper.clinit_called_for_BytePairWrapperWrapper = true; + } + @NullRestricted + BytePairWrapper bpw; + + public String toString() { + return "Wrapping {" + bpw.toString() + "}"; + } + + public int compareTo(BytePairWrapperWrapper other) { + return bpw.compareTo(other.bpw); + } + + public BytePairWrapperWrapper(int b0, int b1) { + bpw = new BytePairWrapper(b0, b1); + super(); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/CharPair.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/CharPair.java new file mode 100644 index 000000000000..b87df18d4e04 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/CharPair.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +public value class CharPair implements Comparable { + static { + ValueClassHelper.clinit_called_for_CharPair = true; + } + char c0, c1; + + public String toString() { + return "(" + c0 + ", " + c1 + ")"; + } + + public int compareTo(CharPair o) { + int n = c0 - o.c0; + if (n != n) { + return n; + } else { + return (c1 - o.c1); + } + } + + public CharPair(char c0, char c1) { + this.c0 = c0; + this.c1 = c1; + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/IntegerWrapper.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/IntegerWrapper.java new file mode 100644 index 000000000000..942a821fa335 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/IntegerWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +public value class IntegerWrapper implements Comparable { + static { + ValueClassHelper.clinit_called_for_IntegerWrapper = true; + } + Integer i; + + public String toString() { + return i.toString(); + } + + public int compareTo(IntegerWrapper o) { + return i - o.i; + } + + public IntegerWrapper(int i) { + this.i = new Integer(i); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPair.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPair.java new file mode 100644 index 000000000000..42c010d4fc39 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPair.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +public value class ShortPair implements Comparable { + static { + ValueClassHelper.clinit_called_for_ShortPair = true; + } + short s0, s1; + + public String toString() { + return "(" + s0 + ", " + s1 + ")"; + } + + public int compareTo(ShortPair o) { + int n = s0 - o.s0; + if (n != n) { + return n; + } else { + return (s1 - o.s1); + } + } + + public ShortPair(int s0, int s1) { + this.s0 = (short)s0; + this.s1 = (short)s1; + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPairWrapper.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPairWrapper.java new file mode 100644 index 000000000000..2652c0c6ecd3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ShortPairWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +import jdk.internal.vm.annotation.NullRestricted; + +public value class ShortPairWrapper implements Comparable { + static { + ValueClassHelper.clinit_called_for_ShortPairWrapper = true; + } + @NullRestricted + ShortPair sp; + + public String toString() { + return "ShortPair: " + sp.toString(); + } + + public int compareTo(ShortPairWrapper other) { + return sp.compareTo(other.sp); + } + + public ShortPairWrapper(int s0, int s1) { + sp = new ShortPair((short)s0, (short)s1); + super(); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ValueClassHelper.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ValueClassHelper.java new file mode 100644 index 000000000000..c442caefba06 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/valueclasses/ValueClassHelper.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package valueclasses; + +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueClassHelper { + static boolean clinit_called_for_BytePair; + static boolean clinit_called_for_BytePairWrapper; + static boolean clinit_called_for_BytePairWrapperWrapper; + static boolean clinit_called_for_CharPair; + static boolean clinit_called_for_IntegerWrapper; + static boolean clinit_called_for_ShortPair; + static boolean clinit_called_for_ShortPairWrapper; + + public static void assertAOTInited_BytePair() { + new BytePair(1, 2); + if (clinit_called_for_BytePair == true) { + throw new RuntimeException("BytePair. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_BytePairWrapper() { + new BytePairWrapper(1, 2); + if (clinit_called_for_BytePairWrapper == true) { + throw new RuntimeException("BytePairWrapper. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_BytePairWrapperWrapper() { + new BytePairWrapperWrapper(1, 2); + if (clinit_called_for_BytePairWrapperWrapper == true) { + throw new RuntimeException("BytePairWrapperWrapper. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_CharPair() { + new CharPair('a', 'b'); + if (clinit_called_for_CharPair == true) { + throw new RuntimeException("CharPair. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_ShortPair() { + new ShortPair((short)0, (short)1); + if (clinit_called_for_ShortPair == true) { + throw new RuntimeException("ShortPair. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_IntegerWrapper() { + new IntegerWrapper(0); + if (clinit_called_for_IntegerWrapper == true) { + throw new RuntimeException("IntegerWrapper. must not execute, as this clas should be AOT-initialized"); + } + } + + public static void assertAOTInited_ShortPairWrapper() { + new ShortPairWrapper(0, 1); + if (clinit_called_for_ShortPairWrapper == true) { + throw new RuntimeException("ShortPairWrapper. must not execute, as this clas should be AOT-initialized"); + } + } + +} From f720c3671a2e09b7ed01cea96872deff59e7faf2 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Fri, 21 Aug 2026 22:04:40 +0000 Subject: [PATCH 035/223] 8390266: Avoid static for the template function in headers Reviewed-by: jsjolen, coleenp, manc, jiangli --- .../share/jfr/recorder/storage/jfrStorageUtils.inline.hpp | 2 +- src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp | 7 +------ src/hotspot/share/oops/accessBackend.hpp | 4 ++-- src/hotspot/share/oops/metadata.hpp | 2 +- src/hotspot/share/utilities/globalDefinitions.hpp | 2 +- src/hotspot/share/utilities/parseInteger.hpp | 4 ++-- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp index 663ce3acd539..ac61b05c4ac7 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp @@ -89,7 +89,7 @@ inline bool MutexedWriteOp::process(typename Operation::Type* t) { } template -static void retired_sensitive_acquire(Type* t, Thread* thread) { +inline void retired_sensitive_acquire(Type* t, Thread* thread) { assert(t != nullptr, "invariant"); assert(thread != nullptr, "invariant"); assert(thread == Thread::current(), "invariant"); diff --git a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp index ff1f4cdd3984..0e7f706b210b 100644 --- a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,11 +49,6 @@ static oop new_java_util_arraylist(TRAPS) { static const int initial_array_size = 64; -template -static GrowableArray* c_heap_allocate_array(int size = initial_array_size) { - return new (mtTracing) GrowableArray(size, mtTracing); -} - static bool initialize(TRAPS) { static bool initialized = false; if (!initialized) { diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp index 368abc7ef25c..a32cf48948f5 100644 --- a/src/hotspot/share/oops/accessBackend.hpp +++ b/src/hotspot/share/oops/accessBackend.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1133,7 +1133,7 @@ namespace AccessInternal { // that the passed in types make sense. template - static void verify_types(){ + inline void verify_types(){ // If this fails to compile, then you have sent in something that is // not recognized as a valid primitive type to a primitive Access function. STATIC_ASSERT((HasDecorator::value || // oops have already been validated diff --git a/src/hotspot/share/oops/metadata.hpp b/src/hotspot/share/oops/metadata.hpp index bd3f17fa3f4f..819e23f97a29 100644 --- a/src/hotspot/share/oops/metadata.hpp +++ b/src/hotspot/share/oops/metadata.hpp @@ -82,7 +82,7 @@ class Metadata : public MetaspaceObj { }; template -static void print_on_maybe_null(outputStream* st, const char* str, const M* m) { +inline void print_on_maybe_null(outputStream* st, const char* str, const M* m) { if (nullptr != m) { st->print_raw(str); m->print_value_on(st); diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 4de462a12873..1198713619dd 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1207,7 +1207,7 @@ inline int build_int_from_shorts( u2 low, u2 high ) { } // swap a & b -template static void swap(T& a, T& b) { +template inline void swap(T& a, T& b) { T tmp = a; a = b; b = tmp; diff --git a/src/hotspot/share/utilities/parseInteger.hpp b/src/hotspot/share/utilities/parseInteger.hpp index 3fc2f62a19fd..30e0d45d1cfb 100644 --- a/src/hotspot/share/utilities/parseInteger.hpp +++ b/src/hotspot/share/utilities/parseInteger.hpp @@ -115,7 +115,7 @@ inline bool multiply_by_1k(T& n) { // Example: "1024M:oom" will yield true, result=1G, endptr pointing to ":oom" template -static bool parse_integer(const char *s, char **endptr, T* result) { +inline bool parse_integer(const char *s, char **endptr, T* result) { if (!isdigit(s[0]) && s[0] != '-') { // strtoll/strtoull may allow leading spaces. Forbid it. @@ -163,7 +163,7 @@ static bool parse_integer(const char *s, char **endptr, T* result) { // characters. No remainder are allowed here. // Example: "100m" - okay, "100m:oom" -> not okay template -static bool parse_integer(const char *s, T* result) { +inline bool parse_integer(const char *s, T* result) { char* remainder; bool rc = parse_integer(s, &remainder, result); rc = rc && (*remainder == '\0'); From 3dcc9e750b68f9e841a9ac1ce70d13dce1ce10f8 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Sat, 22 Aug 2026 06:20:39 +0000 Subject: [PATCH 036/223] 8389968: (dc) DatagramChannel.open() attempts to disable IPPROTO_IPV6/IP_MULTICAST_ALL (lnx) Reviewed-by: michaelm --- src/java.base/unix/native/libnio/ch/Net.c | 28 +++++++---------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c index fe0866027f2f..0779294cdae3 100644 --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -299,11 +299,10 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, } #if defined(__linux__) - if (type == SOCK_DGRAM) { + /* IPv4 or IPv6 datagram socket: disable IP_MULTICAST_ALL (Linux 2.6.31) */ + if (type == SOCK_DGRAM && ipv4_available()) { int arg = 0; - int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; - if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && - (errno != ENOPROTOOPT)) { + if ((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0)) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Unable to set IP_MULTICAST_ALL"); @@ -312,25 +311,14 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, } } - if (domain == AF_INET6 && type == SOCK_DGRAM) { - /* By default, Linux uses the route default */ - int arg = 1; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, - sizeof(arg)) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unable to set IPV6_MULTICAST_HOPS"); - close(fd); - return -1; - } - - /* Disable IPV6_MULTICAST_ALL if option supported */ - arg = 0; + /* IPv6 datagram socket: disable IPV6_MULTICAST_ALL (Linux 4.20) if supported */ + if (type == SOCK_DGRAM && domain == AF_INET6) { + int arg = 0; if ((setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && (errno != ENOPROTOOPT)) { JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unable to set IPV6_MULTICAST_ALL"); + JNU_JAVANETPKG "SocketException", + "Unable to set IPV6_MULTICAST_ALL"); close(fd); return -1; } From 3e3b06dbb07cc74076d1674dd2abc5540d600d3c Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Sat, 22 Aug 2026 10:34:06 +0000 Subject: [PATCH 037/223] 8390370: [Valhalla] PPC64 C1 LIR_Assembler::emit_alloc_array() doesn't check LIR_OpAllocArray::always_slow_path() Reviewed-by: mdoerr --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 8f2eb05cbd5a..d6051da562a3 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2250,7 +2250,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { LP64_ONLY( __ extsw(op->len()->as_register(), op->len()->as_register()); ) - if (UseSlowPath || + if (UseSlowPath || op->always_slow_path() || (!UseFastNewObjectArray && (is_reference_type(op->type()))) || (!UseFastNewTypeArray && (!is_reference_type(op->type())))) { __ b(*op->stub()->entry()); From 921ea73d0c4b0b7ee55fc2aa9be25059cd70d6f0 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Sun, 23 Aug 2026 01:12:16 +0000 Subject: [PATCH 038/223] 8390614: RISC-V: Support VerifyOops for AOT caching stub and code Reviewed-by: adinn, fyang, kvn --- .../gc/shared/barrierSetAssembler_riscv.cpp | 17 ++++++-- .../shenandoahBarrierSetAssembler_riscv.cpp | 22 ++++++++-- .../riscv/gc/z/zBarrierSetAssembler_riscv.cpp | 17 ++++++-- .../cpu/riscv/macroAssembler_riscv.cpp | 43 ++++++++++++------- 4 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 2139ffd52345..f0f5abbfcaf9 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -24,6 +24,7 @@ */ #include "classfile/classLoaderData.hpp" +#include "code/aotCodeCache.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/barrierSetNMethod.hpp" @@ -372,10 +373,20 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { } void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { + assert_different_registers(obj, tmp1, tmp2); // Check if the oop is in the right area of memory - __ mv(tmp2, (intptr_t) Universe::verify_oop_mask()); - __ andr(tmp1, obj, tmp2); - __ mv(tmp2, (intptr_t) Universe::verify_oop_bits()); +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump()) { + __ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address())); + __ andr(tmp1, obj, tmp2); + __ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address())); + } else +#endif + { + __ mv(tmp2, (intptr_t) Universe::verify_oop_mask()); + __ andr(tmp1, obj, tmp2); + __ mv(tmp2, (intptr_t) Universe::verify_oop_bits()); + } // Compare tmp1 and tmp2. __ bne(tmp1, tmp2, error); diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index 647846d523b2..03841fa48cb5 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -24,6 +24,7 @@ * */ +#include "code/aotCodeCache.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" @@ -219,11 +220,14 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, // Test for in-cset if (is_strong) { +#if INCLUDE_CDS if (AOTCodeCache::is_on_for_dump()) { __ ld(t1, ExternalAddress(AOTRuntimeConstants::cset_base_address())); __ lwu(t0, ExternalAddress(AOTRuntimeConstants::grain_shift_address())); __ srl(t0, x10, t0); - } else { + } else +#endif + { __ mv(t1, ShenandoahHeap::in_cset_fast_test_addr()); __ srli(t0, x10, ShenandoahHeapRegion::region_size_bytes_shift_jint()); } @@ -440,10 +444,20 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl } void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) { + assert_different_registers(obj, tmp1, tmp2); // Check if the oop is in the right area of memory - __ mv(tmp2, (intptr_t) Universe::verify_oop_mask()); - __ andr(tmp1, obj, tmp2); - __ mv(tmp2, (intptr_t) Universe::verify_oop_bits()); +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump()) { + __ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address())); + __ andr(tmp1, obj, tmp2); + __ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address())); + } else +#endif + { + __ mv(tmp2, (intptr_t) Universe::verify_oop_mask()); + __ andr(tmp1, obj, tmp2); + __ mv(tmp2, (intptr_t) Universe::verify_oop_bits()); + } // Compare tmp1 and tmp2. __ bne(tmp1, tmp2, L_error); diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index 143a7e765911..9fbc59fe5ce3 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -24,6 +24,7 @@ */ #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeBlob.hpp" #include "code/vmreg.inline.hpp" #include "gc/z/zAddress.hpp" @@ -1007,6 +1008,7 @@ void ZBarrierSetAssembler::generate_c1_store_barrier_stub(LIR_Assembler* ce, #define __ masm-> void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { + assert_different_registers(obj, tmp1, tmp2); // C1 calls verify_oop in the middle of barriers, before they have been uncolored // and after being colored. Therefore, we must deal with colored oops as well. Label done; @@ -1044,9 +1046,18 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe __ bind(check_zaddress); // Check if the oop is the right area of memory - __ mv(tmp1, (intptr_t) Universe::verify_oop_mask()); - __ andr(tmp1, tmp1, obj); - __ mv(obj, (intptr_t) Universe::verify_oop_bits()); +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump()) { + __ ld(tmp1, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address())); + __ andr(tmp1, tmp1, obj); + __ ld(obj, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address())); + } else +#endif + { + __ mv(tmp1, (intptr_t) Universe::verify_oop_mask()); + __ andr(tmp1, tmp1, obj); + __ mv(obj, (intptr_t) Universe::verify_oop_bits()); + } __ bne(tmp1, obj, error); __ bind(done); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 15d853f919b5..b245f2650eb0 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -28,6 +28,7 @@ #include "asm/assembler.inline.hpp" #include "cds/archiveBuilder.hpp" #include "ci/ciInlineKlass.hpp" +#include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" @@ -523,20 +524,25 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, ResourceMark rm; stringStream ss; ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line); - b = code_string(ss.as_string()); +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) { + // This will duplicate string to preserve it. + b = AOTCodeCache::add_C_string(ss.as_string()); + } else +#endif + { + b = code_string(ss.as_string()); + } } BLOCK_COMMENT("verify_oop {"); push_reg(RegSet::of(ra, t0, t1, c_rarg0), sp); mv(c_rarg0, reg); // c_rarg0 : x10 - { - // The length of the instruction sequence emitted should not depend - // on the address of the char buffer so that the size of mach nodes for - // scratch emit and normal emit matches. - IncompressibleScope scope(this); // Fixed length - movptr(t0, (address) b); - } + // The length of the instruction sequence emitted should not depend + // on the address of the char buffer so that the size of mach nodes for + // scratch emit and normal emit matches. + la(t0, ExternalAddress((address)b)); // Call indirectly to solve generation ordering problem ld(t1, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -709,7 +715,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f ResourceMark rm; stringStream ss; ss.print("verify_oop_addr: %s (%s:%d)", s, file, line); - b = code_string(ss.as_string()); +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) { + // This will duplicate string to preserve it. + b = AOTCodeCache::add_C_string(ss.as_string()); + } else +#endif + { + b = code_string(ss.as_string()); + } } BLOCK_COMMENT("verify_oop_addr {"); @@ -722,13 +736,10 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f ld(x10, addr); } - { - // The length of the instruction sequence emitted should not depend - // on the address of the char buffer so that the size of mach nodes for - // scratch emit and normal emit matches. - IncompressibleScope scope(this); // Fixed length - movptr(t0, (address) b); - } + // The length of the instruction sequence emitted should not depend + // on the address of the char buffer so that the size of mach nodes for + // scratch emit and normal emit matches. + la(t0, ExternalAddress((address)b)); // Call indirectly to solve generation ordering problem ld(t1, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); From d1562ff2d8303d32a6603c85039b99ff798affdb Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Sun, 23 Aug 2026 11:00:22 +0000 Subject: [PATCH 039/223] 8370914: C2: Reimplement Type::meet and Type::join Co-authored-by: Tobias Hartmann Reviewed-by: thartmann, chagedorn, dlong, mchevalier --- src/hotspot/share/opto/addnode.cpp | 13 +- src/hotspot/share/opto/castnode.cpp | 9 + src/hotspot/share/opto/compile.cpp | 10 +- src/hotspot/share/opto/compile.hpp | 4 +- src/hotspot/share/opto/graphKit.cpp | 76 +- src/hotspot/share/opto/library_call.cpp | 2 +- src/hotspot/share/opto/memnode.cpp | 17 +- src/hotspot/share/opto/parse2.cpp | 37 +- src/hotspot/share/opto/rangeinference.cpp | 75 +- src/hotspot/share/opto/rangeinference.hpp | 5 +- src/hotspot/share/opto/subnode.cpp | 5 +- src/hotspot/share/opto/type.cpp | 2924 ++++++----------- src/hotspot/share/opto/type.hpp | 318 +- src/hotspot/share/opto/typejavaptr.hpp | 818 +++++ .../share/utilities/globalDefinitions.hpp | 2 +- test/hotspot/gtest/opto/test_typejavaptr.cpp | 2003 +++++++++++ .../compiler/types/TestMeetInstanceId.java | 63 + .../types/TestSameArrayDifferentViews.java | 54 + .../inlinetypes/TestNullableArrays.java | 2 +- 19 files changed, 4181 insertions(+), 2256 deletions(-) create mode 100644 src/hotspot/share/opto/typejavaptr.hpp create mode 100644 test/hotspot/gtest/opto/test_typejavaptr.cpp create mode 100644 test/hotspot/jtreg/compiler/types/TestMeetInstanceId.java create mode 100644 test/hotspot/jtreg/compiler/types/TestSameArrayDifferentViews.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index ebb41e552a2a..31fcc46e0cb4 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -852,11 +852,14 @@ const Type *AddPNode::bottom_type() const { if (in(Address) == nullptr) return TypePtr::BOTTOM; const TypePtr *tp = in(Address)->bottom_type()->isa_ptr(); if( !tp ) return Type::TOP; // TOP input means TOP output - assert( in(Offset)->Opcode() != Op_ConP, "" ); - const Type *t = in(Offset)->bottom_type(); - if( t == Type::TOP ) - return tp->add_offset(Type::OffsetTop); - const TypeX *tx = t->is_intptr_t(); + + assert(in(Offset)->Opcode() != Op_ConP, ""); + const Type* t = in(Offset)->bottom_type(); + if (t == Type::TOP) { + return Type::TOP; + } + + const TypeX* tx = t->is_intptr_t(); intptr_t txoffset = Type::OffsetBot; if (tx->is_con()) { // Left input is an add of a constant? txoffset = tx->get_con(); diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index c10f5b2eb300..472780bb96dd 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -204,6 +204,11 @@ TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) bool ConstraintCastNode::higher_equal_types(PhaseGVN* phase, const Node* other) const { const Type* t = phase->type(other); + if ((t->isa_rawptr() && (type()->isa_oopptr() || type()->isa_klassptr())) || + ((t->isa_oopptr() || t->isa_klassptr()) && type()->isa_rawptr())) { + assert(is_CheckCastPP(), "unrelated types from %s", Name()); + return false; + } if (!t->higher_equal_speculative(type())) { return false; } @@ -224,6 +229,10 @@ Node* ConstraintCastNode::pin_node_under_control_impl() const { Node* ConstraintCastNode::ideal_cast_of_inline_type_node(PhaseGVN* phase) { InlineTypeNode* vt = in(1)->as_InlineType(); + if (type()->isa_rawptr() != nullptr) { + return nullptr; + } + const Type* join = vt->type()->filter(type()); if (join == Type::TOP) { // Do not push a dead Cast since its type can be unrelated diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 6ad48eda201c..dc457ca4b3b4 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1442,7 +1442,7 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { } // Remove size and stability - const TypeAry* normalized_ary = TypeAry::make(ta->elem(), TypeInt::POS, false, ta->is_flat(), ta->is_not_flat(), ta->is_not_null_free(), ta->is_atomic()); + const TypeAry* normalized_ary = TypeAry::make(ta->elem(), TypeInt::POS, false, ta->is_flat(), ta->is_not_flat(), ta->is_null_free(), ta->is_not_null_free(), ta->is_atomic()); // Remove ptr, const_oop, and offset if (ta->elem() == Type::BOTTOM) { // Bottom array (meet of int[] and byte[] for example), accesses to it will be done with @@ -1465,7 +1465,7 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { // All arrays of references share the same slice if (!ta->is_flat() && ta->elem()->make_oopptr() != nullptr) { - const TypeAry* tary = TypeAry::make(TypeInstPtr::BOTTOM, TypeInt::POS, false, false, true, true, true); + const TypeAry* tary = TypeAry::make(TypeInstPtr::BOTTOM, TypeInt::POS, false, false, true, false, true, true); tj = ta = TypeAryPtr::make(TypePtr::BotPTR, nullptr, tary, nullptr, false, Type::Offset::bottom); } @@ -1726,7 +1726,7 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr Type::str(adr_type), Type::str(flat), Type::str(flatten_alias_type(flat))); assert(flat != TypePtr::BOTTOM, "cannot alias-analyze an untyped ptr: adr_type = %s", Type::str(adr_type)); - if (flat->isa_oopptr() && !flat->isa_klassptr()) { + if (flat->isa_instptr()) { const TypeOopPtr* foop = flat->is_oopptr(); // Scalarizable allocations have exact klass always. bool exact = !foop->klass_is_exact() || foop->is_known_instance(); @@ -6072,10 +6072,10 @@ void Compile::igv_print_graph_to_network(const char* name, GrowableArraytype(value)->higher_equal(type)) { + if (type->base() == Type::Int && phase->type(value)->higher_equal(type)) { return value; } + Node* result = nullptr; if (bt == T_BYTE) { result = phase->transform(new LShiftINode(value, phase->intcon(24))); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index f3189b6ba40a..f931deaad344 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -104,7 +104,7 @@ class InlineTypeNode; class nmethod; class Node_Stack; struct Final_Reshape_Counts; -class VerifyMeetResult; +class VerifyMeetJoinResult; enum LoopOptsMode { LoopOptsDefault, @@ -1392,7 +1392,7 @@ class Compile : public Phase { bool needs_clinit_barrier(ciInstanceKlass* ik, ciMethod* accessing_method); #ifdef ASSERT - VerifyMeetResult* _type_verify; + VerifyMeetJoinResult* _type_verify; void set_exception_backedge() { _exception_backedge = true; } bool has_exception_backedge() const { return _exception_backedge; } #endif diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index a2da4efa2a1b..81b9fa501665 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -59,6 +59,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/powerOfTwo.hpp" @@ -3976,6 +3977,15 @@ Node* GraphKit::flat_array_test(Node* array_or_klass, bool flat) { } Node* GraphKit::null_free_array_test(Node* array, bool null_free) { + const TypeAryPtr* array_type = gvn().type(array)->isa_aryptr(); + if (array_type != nullptr) { + if (array_type->is_null_free()) { + return intcon(null_free); + } else if (array_type->is_not_null_free()) { + return intcon(!null_free); + } + } + return mark_word_test(array, markWord::null_free_array_bit_in_place, null_free); } @@ -3988,6 +3998,15 @@ Node* GraphKit::null_free_atomic_array_test(Node* array, ciInlineKlass* vk) { return intcon(0); // Never atomic } + const TypeAryPtr* array_type = gvn().type(array)->isa_aryptr(); + if (array_type != nullptr) { + if (array_type->is_atomic()) { + return intcon(1); + } else if (array_type->klass_is_exact() && !array_type->is_atomic()) { + return intcon(0); + } + } + Node* array_klass = load_object_klass(array); int layout_kind_offset = in_bytes(FlatArrayKlass::layout_kind_offset()); Node* layout_kind_addr = basic_plus_adr(top(), array_klass, layout_kind_offset); @@ -4230,33 +4249,19 @@ void GraphKit::shared_unlock(Node* box, Node* obj) { Node* GraphKit::get_layout_helper(Node* klass_node, jint& constant_value) { const TypeKlassPtr* klass_t = _gvn.type(klass_node)->isa_klassptr(); if (!StressReflectiveCode && klass_t != nullptr) { - bool xklass = klass_t->klass_is_exact(); - bool can_be_flat = false; - const TypeAryPtr* ary_type = klass_t->as_exact_instance_type()->isa_aryptr(); - if (UseArrayFlattening && !xklass && ary_type != nullptr) { - // Don't constant fold if the runtime type might be a flat array but the static type is not. - const TypeOopPtr* elem = ary_type->elem()->make_oopptr(); - can_be_flat = ary_type->can_be_inline_array() && (!elem->is_inlinetypeptr() || elem->inline_klass()->maybe_flat_in_array()); + if (klass_t->klass_is_exact()) { + constant_value = klass_t->exact_klass()->layout_helper(); + return nullptr; } - if (!can_be_flat && (xklass || (klass_t->isa_aryklassptr() && klass_t->is_aryklassptr()->elem() != Type::BOTTOM))) { - jint lhelper; - if (klass_t->is_flat()) { - lhelper = ary_type->flat_layout_helper(); - } else if (klass_t->isa_aryklassptr()) { - BasicType elem = ary_type->elem()->array_element_basic_type(); - if (is_reference_type(elem, true)) { - elem = T_OBJECT; - } - lhelper = Klass::array_layout_helper(elem); - } else { - lhelper = klass_t->is_instklassptr()->exact_klass()->layout_helper(); - } - if (lhelper != Klass::_lh_neutral_value) { - constant_value = lhelper; - return (Node*) nullptr; - } + + const TypeAryKlassPtr* aryklass_t = klass_t->isa_aryklassptr(); + if (aryklass_t != nullptr && aryklass_t->elem()->isa_klassptr() != nullptr && aryklass_t->is_not_flat()) { + // If we know that the array cannot be flat, then the layout_helper value is known + constant_value = Klass::array_layout_helper(T_OBJECT); + return nullptr; } } + constant_value = Klass::_lh_neutral_value; // put in a known value Node* lhp = off_heap_plus_addr(klass_node, in_bytes(Klass::layout_helper_offset())); return make_load(nullptr, lhp, TypeInt::INT, T_INT, MemNode::unordered); @@ -4436,13 +4441,6 @@ Node* GraphKit::new_instance(Node* klass_node, (*return_size_val) = size; } - // This is a precise notnull oop of the klass. - // (Actually, it need not be precise if this is a reflective allocation.) - // It's what we cast the result to. - const TypeKlassPtr* tklass = _gvn.type(klass_node)->isa_klassptr(); - if (!tklass) tklass = TypeInstKlassPtr::OBJECT; - const TypeOopPtr* oop_type = tklass->as_exact_instance_type(); - // Now generate allocation code // The entire memory state is needed for slow path of the allocation @@ -4455,6 +4453,20 @@ Node* GraphKit::new_instance(Node* klass_node, size, klass_node, initial_slow_test, inline_type_node); + // This is a precise notnull oop of the klass. + // (Actually, it need not be precise if this is a reflective allocation.) + // It's what we cast the result to. + const TypeInstKlassPtr* tklass = _gvn.type(klass_node)->isa_instklassptr(); + const TypeOopPtr* oop_type; + if (tklass == nullptr) { + oop_type = TypeInstPtr::BOTTOM; + } else if (tklass->klass_is_exact() && (tklass->instance_klass()->is_abstract() || !tklass->interfaces()->eq(tklass->instance_klass()))) { + // tklass may be an abstract class or an interface, for which we cannot make a TypeOopPtr + oop_type = TypeInstPtr::BOTTOM; + } else { + oop_type = tklass->as_exact_instance_type(); + } + return set_output_for_allocation(alloc, oop_type, deoptimize_on_exception); } @@ -4816,7 +4828,7 @@ Node* GraphKit::load_String_value(Node* str, bool set_ctrl) { false, nullptr, Type::Offset(0)); const TypePtr* value_field_type = string_type->add_offset(value_offset); const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::BotPTR, - TypeAry::make(TypeInt::BYTE, TypeInt::POS, false, false, true, true, true), + TypeAry::make(TypeInt::BYTE, TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_BYTE), true, Type::Offset(0)); Node* p = basic_plus_adr(str, str, value_offset); Node* load = access_load_at(str, p, value_field_type, value_type, T_OBJECT, diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 36d69f18041b..f91077c9e174 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4240,7 +4240,7 @@ bool LibraryCallKit::inline_native_setCurrentThread() { const Type* LibraryCallKit::scopedValueCache_type() { ciKlass* objects_klass = ciObjArrayKlass::make(env()->Object_klass()); const TypeOopPtr* etype = TypeOopPtr::make_from_klass(env()->Object_klass()); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ false, /* not_flat= */ true, /* not_null_free= */ true, true); + const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ false, /* not_flat= */ true, /*null_free=*/ false, /* not_null_free= */ true, true); // Because we create the scopedValue cache lazily we have to make the // type of the result BotPTR. diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index d90d01175f75..dbd975200844 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1249,10 +1249,21 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { Node* ctl = ac->in(0); Node* src = ac->in(ArrayCopyNode::Src); - if (!ac->as_ArrayCopy()->is_clonebasic() && !phase->type(src)->isa_aryptr()) { + const TypeAryPtr* dst_arytype = phase->type(ac->in(ArrayCopyNode::Dest))->isa_aryptr(); + const TypeAryPtr* src_arytype = phase->type(src)->isa_aryptr(); + if (src_arytype == nullptr && !ac->as_ArrayCopy()->is_clonebasic()) { return nullptr; } + if (src_arytype != nullptr && dst_arytype != nullptr) { + // Cannot transform if the layouts are different + bool may_transform = (src_arytype->is_not_flat() && dst_arytype->is_not_flat()) || + (src_arytype->klass_is_exact() && dst_arytype->klass_is_exact() && src_arytype->exact_klass() == dst_arytype->exact_klass()); + if (!may_transform) { + return nullptr; + } + } + // load depends on the tests that validate the arraycopy LoadNode* ld = clone_pinned(); Node* addp = in(MemNode::Address)->clone(); @@ -2337,6 +2348,10 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { assert(off != Type::OffsetTop, "case covered by TypePtr::empty"); Compile* C = phase->C; + if (is_mismatched_access()) { + return _type; + } + // If load can see a previous constant store, use that. Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con()) { diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 9c194774421a..133744ee8bca 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -125,8 +125,16 @@ void Parse::array_load(BasicType bt) { if (element_ptr->is_inlinetypeptr()) { ciInlineKlass* vk = element_ptr->inline_klass(); Node* flat_array = cast_to_flat_array(array, vk); - Node* vt = InlineTypeNode::make_from_flat_array(this, vk, flat_array, array_index); - ideal.set(res, vt); + + // It may be the case that array is only known to be not flat when we try to cast it to a + // flat array. For example, array is a not-null-free array and vk does not have a + // nullable layout. + if (!flat_array->is_top()) { + Node* vt = InlineTypeNode::make_from_flat_array(this, vk, flat_array, array_index); + ideal.set(res, vt); + } else { + ideal.set(res, InlineTypeNode::make_null(gvn(), vk)); + } } else { // Element type is unknown, and thus we cannot statically determine the exact flat array layout. Emit a // runtime call to correctly load the inline type element from the flat array. @@ -290,17 +298,22 @@ void Parse::array_store(BasicType bt) { // Element type is known, cast and store to flat array layout. Node* flat_array = cast_to_flat_array(array, vk); - // Re-execute flat array store if buffering triggers deoptimization - PreserveReexecuteState preexecs(this); - jvms()->set_should_reexecute(true); - inc_sp(3); - - if (!stored_value_casted->is_InlineType()) { - assert(_gvn.type(stored_value_casted) == TypePtr::NULL_PTR, "Unexpected value"); - stored_value_casted = InlineTypeNode::make_null(_gvn, vk); + // It may be the case that array is only known to be not flat when we try to cast it to + // a flat array. For example, array is a not-null-free array and vk does not have a + // nullable layout. + if (!flat_array->is_top()) { + // Re-execute flat array store if buffering triggers deoptimization + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + inc_sp(3); + + if (!stored_value_casted->is_InlineType()) { + assert(_gvn.type(stored_value_casted) == TypePtr::NULL_PTR, "Unexpected value"); + stored_value_casted = InlineTypeNode::make_null(_gvn, vk); + } + + stored_value_casted->as_InlineType()->store_flat_array(this, flat_array, array_index); } - - stored_value_casted->as_InlineType()->store_flat_array(this, flat_array, array_index); } else { // Element type is unknown, emit a runtime call since the flat array layout is not statically known. store_to_unknown_flat_array(array, array_index, stored_value_casted); diff --git a/src/hotspot/share/opto/rangeinference.cpp b/src/hotspot/share/opto/rangeinference.cpp index cb26e68ef588..89c74e888b66 100644 --- a/src/hotspot/share/opto/rangeinference.cpp +++ b/src/hotspot/share/opto/rangeinference.cpp @@ -690,69 +690,24 @@ template class TypeIntPrototype, uintn_t<4>>; template class TypeIntPrototype, uintn_t<5>>; template class TypeIntPrototype, uintn_t<6>>; -// Compute the meet of 2 types. When dual is true, the subset relation in CT is -// reversed. This means that the result of 2 CTs would be the intersection of -// them if dual is true, and be the union of them if dual is false. The subset -// relation in the Type hierarchy is still the same, however. E.g. the result -// of 1 CT and Type::BOTTOM would always be Type::BOTTOM, and the result of 1 -// CT and Type::TOP would always be the CT instance itself. template -const Type* TypeIntHelper::int_type_xmeet(const CT* i1, const Type* t2) { - // Perform a fast test for common case; meeting the same types together. - if (i1 == t2 || t2 == Type::TOP) { - return i1; - } - const CT* i2 = t2->try_cast(); - if (i2 != nullptr) { - assert(i1->_is_dual == i2->_is_dual, "must have the same duality"); - using S = std::remove_const_t; - using U = std::remove_const_t; - - if (!i1->_is_dual) { - // meet (a.k.a union) - return int_type_union(i1, i2); - } else { - // join (a.k.a intersection) - return CT::make_or_top(TypeIntPrototype{{MAX2(i1->_lo, i2->_lo), MIN2(i1->_hi, i2->_hi)}, - {MAX2(i1->_ulo, i2->_ulo), MIN2(i1->_uhi, i2->_uhi)}, - {i1->_bits._zeros | i2->_bits._zeros, i1->_bits._ones | i2->_bits._ones}}, - MIN2(i1->_widen, i2->_widen), true); - } - } +const Type* TypeIntHelper::int_type_xmeet(const CT* t1, const CT* t2) { + return int_type_union(t1, t2); +} +template const Type* TypeIntHelper::int_type_xmeet(const TypeInt* i1, const TypeInt* t2); +template const Type* TypeIntHelper::int_type_xmeet(const TypeLong* i1, const TypeLong* t2); - assert(t2->base() != i1->base(), ""); - switch (t2->base()) { // Switch on original type - case Type::AnyPtr: // Mixing with oops happens when javac - case Type::RawPtr: // reuses local variables - case Type::OopPtr: - case Type::InstPtr: - case Type::AryPtr: - case Type::MetadataPtr: - case Type::KlassPtr: - case Type::InstKlassPtr: - case Type::AryKlassPtr: - case Type::NarrowOop: - case Type::NarrowKlass: - case Type::Int: - case Type::Long: - case Type::HalfFloatTop: - case Type::HalfFloatCon: - case Type::HalfFloatBot: - case Type::FloatTop: - case Type::FloatCon: - case Type::FloatBot: - case Type::DoubleTop: - case Type::DoubleCon: - case Type::DoubleBot: - case Type::Bottom: // Ye Olde Default - return Type::BOTTOM; - default: // All else is a mistake - i1->typerr(t2); - return nullptr; - } +template +const Type* TypeIntHelper::int_type_xjoin(const CT* t1, const CT* t2) { + using S = std::remove_const_t; + using U = std::remove_const_t; + return CT::make_or_top(TypeIntPrototype{{MAX2(t1->_lo, t2->_lo), MIN2(t1->_hi, t2->_hi)}, + {MAX2(t1->_ulo, t2->_ulo), MIN2(t1->_uhi, t2->_uhi)}, + {t1->_bits._zeros | t2->_bits._zeros, t1->_bits._ones | t2->_bits._ones}}, + MIN2(t1->_widen, t2->_widen)); } -template const Type* TypeIntHelper::int_type_xmeet(const TypeInt* i1, const Type* t2); -template const Type* TypeIntHelper::int_type_xmeet(const TypeLong* i1, const Type* t2); +template const Type* TypeIntHelper::int_type_xjoin(const TypeInt* i1, const TypeInt* t2); +template const Type* TypeIntHelper::int_type_xjoin(const TypeLong* i1, const TypeLong* t2); // Called in PhiNode::Value during CCP, monotically widen the value set, do so rigorously // first, after WidenMax attempts, if the type has still not converged we speed up the diff --git a/src/hotspot/share/opto/rangeinference.hpp b/src/hotspot/share/opto/rangeinference.hpp index e5e34051587e..09eb5750d6d9 100644 --- a/src/hotspot/share/opto/rangeinference.hpp +++ b/src/hotspot/share/opto/rangeinference.hpp @@ -145,7 +145,10 @@ class TypeIntHelper { } template - static const Type* int_type_xmeet(const CT* i1, const Type* t2); + static const Type* int_type_xmeet(const CT* i1, const CT* t2); + + template + static const Type* int_type_xjoin(const CT* i1, const CT* t2); template static auto int_type_union(CTP t1, CTP t2) { diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index a58e1cf5e2a1..d45bfa235686 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -2118,8 +2118,9 @@ const Type* AbsNode::Value(PhaseGVN* phase) const { Node* AbsNode::Identity(PhaseGVN* phase) { Node* in1 = in(1); // No need to do abs for non-negative values - if (phase->type(in1)->higher_equal(TypeInt::POS) || - phase->type(in1)->higher_equal(TypeLong::POS)) { + const Type* in_type = phase->type(in1); + if ((in_type->isa_int() && in_type->is_int()->_lo >= 0) || + (in_type->isa_long() && in_type->is_long()->_lo >= 0)) { return in1; } // Convert "abs(abs(x))" into "abs(x)" diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index ec13d305228d..7f39d1de985b 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -27,35 +27,34 @@ #include "ci/ciFlatArrayKlass.hpp" #include "ci/ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" +#include "ci/ciMetadata.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciObject.hpp" #include "ci/ciTypeFlow.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" -#include "classfile/vmSymbols.hpp" #include "compiler/compileLog.hpp" #include "libadt/dict.hpp" -#include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" -#include "oops/instanceKlass.hpp" #include "oops/instanceMirrorKlass.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/typeArrayKlass.hpp" #include "opto/arraycopynode.hpp" #include "opto/callnode.hpp" +#include "opto/compile.hpp" #include "opto/matcher.hpp" #include "opto/node.hpp" #include "opto/opcodes.hpp" #include "opto/rangeinference.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" +#include "opto/typejavaptr.hpp" #include "runtime/globals.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" -#include "utilities/powerOfTwo.hpp" #include "utilities/stringUtils.hpp" // Portions of code courtesy of Clifford Click @@ -64,8 +63,6 @@ // Dictionary of types shared among compilations. Dict* Type::_shared_type_dict = nullptr; -const Type::Offset Type::Offset::top(Type::OffsetTop); -const Type::Offset Type::Offset::bottom(Type::OffsetBot); const Type::Offset Type::Offset::meet(const Type::Offset other) const { // Either is 'TOP' offset? Return the other offset! @@ -76,10 +73,17 @@ const Type::Offset Type::Offset::meet(const Type::Offset other) const { return Offset(_offset); } -const Type::Offset Type::Offset::dual() const { - if (_offset == OffsetTop) return bottom;// Map 'TOP' into 'BOTTOM' - if (_offset == OffsetBot) return top;// Map 'BOTTOM' into 'TOP' - return Offset(_offset); // Map everything else into self +const Type::Offset Type::Offset::join(const Type::Offset other) const { + if (*this == bottom) { + return other; + } else if (other == bottom) { + return *this; + } + if (*this != other) { + return top; + } else { + return *this; + } } const Type::Offset Type::Offset::add(intptr_t offset) const { @@ -690,10 +694,10 @@ void Type::Initialize_shared(Compile* current) { TypeAryPtr::_array_interfaces = TypeInterfaces::make(&array_interfaces); TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces; - TypeAryPtr::BOTTOM = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS, false, false, false, false, false), nullptr, false, Offset::bottom); - TypeAryPtr::RANGE = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS, false, false, false, false, false), nullptr /* current->env()->Object_klass() */, false, Offset(arrayOopDesc::length_offset_in_bytes())); + TypeAryPtr::BOTTOM = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS, false, false, false, false, false, false), nullptr, false, Offset::bottom); + TypeAryPtr::RANGE = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS, false, false, false, false, false, false), nullptr /* current->env()->Object_klass() */, false, Offset(arrayOopDesc::length_offset_in_bytes())); - TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/, false, Offset::bottom); + TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS, false, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/, false, Offset::bottom); #ifdef _LP64 if (UseCompressedOops) { @@ -703,16 +707,16 @@ void Type::Initialize_shared(Compile* current) { #endif { // There is no shared klass for Object[]. See note in TypeAryPtr::klass(). - TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/, false, Offset::bottom); + TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, false, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/, false, Offset::bottom); } - TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_BYTE), true, Offset::bottom); - TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_SHORT), true, Offset::bottom); - TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_CHAR), true, Offset::bottom); - TypeAryPtr::INTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_INT), true, Offset::bottom); - TypeAryPtr::LONGS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_LONG), true, Offset::bottom); - TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_FLOAT), true, Offset::bottom); - TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_DOUBLE), true, Offset::bottom); - TypeAryPtr::INLINES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, /* stable= */ false, /* flat= */ true, false, false, false), nullptr, false, Offset::bottom); + TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_BYTE), true, Offset::bottom); + TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_SHORT), true, Offset::bottom); + TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_CHAR), true, Offset::bottom); + TypeAryPtr::INTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_INT), true, Offset::bottom); + TypeAryPtr::LONGS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_LONG), true, Offset::bottom); + TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_FLOAT), true, Offset::bottom); + TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS, false, false, true, false, true, true), ciTypeArrayKlass::make(T_DOUBLE), true, Offset::bottom); + TypeAryPtr::INLINES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, /* stable= */ false, /* flat= */ true, false, false, false, false), nullptr, false, Offset::bottom); // Nobody should ask _array_body_type[T_NARROWOOP]. Use null as assert. TypeAryPtr::_array_body_type[T_NARROWOOP] = nullptr; @@ -855,40 +859,18 @@ void Type::Initialize(Compile* current) { // Do the hash-cons trick. If the Type already exists in the type table, // delete the current Type and return the existing Type. Otherwise stick the // current Type in the Type table. -const Type *Type::hashcons(void) { +const Type* Type::hashcons() { DEBUG_ONLY(base()); // Check the assertion in Type::base(). // Look up the Type in the Type dictionary - Dict *tdic = type_dict(); + Dict* tdic = type_dict(); Type* old = (Type*)(tdic->Insert(this, this, false)); - if( old ) { // Pre-existing Type? - if( old != this ) // Yes, this guy is not the pre-existing? - delete this; // Yes, Nuke this guy - assert( old->_dual, "" ); - return old; // Return pre-existing - } - - // Every type has a dual (to make my lattice symmetric). - // Since we just discovered a new Type, compute its dual right now. - assert( !_dual, "" ); // No dual yet - _dual = xdual(); // Compute the dual - if (equals(this, _dual)) { // Handle self-symmetric - if (_dual != this) { - delete _dual; - _dual = this; - } + if (old == nullptr) { return this; } - assert( !_dual->_dual, "" ); // No reverse dual yet - assert( !(*tdic)[_dual], "" ); // Dual not in type system either - // New Type, insert into Type table - tdic->Insert((void*)_dual,(void*)_dual); - ((Type*)_dual)->_dual = this; // Finish up being symmetric -#ifdef ASSERT - Type *dual_dual = (Type*)_dual->xdual(); - assert( eq(dual_dual), "xdual(xdual()) should be identity" ); - delete dual_dual; -#endif - return this; // Return new Type + if (old != this) { + delete this; + } + return old; } //------------------------------eq--------------------------------------------- @@ -916,35 +898,35 @@ bool Type::is_nan() const { } #ifdef ASSERT -class VerifyMeet; -class VerifyMeetResult : public ArenaObj { - friend class VerifyMeet; +class VerifyMeetJoin; +class VerifyMeetJoinResult : public ArenaObj { + friend class VerifyMeetJoin; friend class Type; private: - class VerifyMeetResultEntry { + class CacheEntry { private: const Type* _in1; const Type* _in2; const Type* _res; public: - VerifyMeetResultEntry(const Type* in1, const Type* in2, const Type* res): + CacheEntry(const Type* in1, const Type* in2, const Type* res): _in1(in1), _in2(in2), _res(res) { } - VerifyMeetResultEntry(): + CacheEntry(): _in1(nullptr), _in2(nullptr), _res(nullptr) { } - bool operator==(const VerifyMeetResultEntry& rhs) const { + bool operator==(const CacheEntry& rhs) const { return _in1 == rhs._in1 && _in2 == rhs._in2 && _res == rhs._res; } - bool operator!=(const VerifyMeetResultEntry& rhs) const { + bool operator!=(const CacheEntry& rhs) const { return !(rhs == *this); } - static int compare(const VerifyMeetResultEntry& v1, const VerifyMeetResultEntry& v2) { + static int compare(const CacheEntry& v1, const CacheEntry& v2) { if ((intptr_t) v1._in1 < (intptr_t) v2._in1) { return -1; } else if (v1._in1 == v2._in1) { @@ -960,302 +942,410 @@ class VerifyMeetResult : public ArenaObj { } const Type* res() const { return _res; } }; + uint _depth; - GrowableArray _cache; - - // With verification code, the meet of A and B causes the computation of: - // 1- meet(A, B) - // 2- meet(B, A) - // 3- meet(dual(meet(A, B)), dual(A)) - // 4- meet(dual(meet(A, B)), dual(B)) - // 5- meet(dual(A), dual(B)) - // 6- meet(dual(B), dual(A)) - // 7- meet(dual(meet(dual(A), dual(B))), A) - // 8- meet(dual(meet(dual(A), dual(B))), B) + GrowableArray _meet_cache; + GrowableArray _join_cache; + + // With verification code, the meet/join of A and B causes the computation of: + // 1- meet(A, B) + // 2- meet(B, A) + // 3- join(A, B) + // 4- join(B, A) + // 5- meet(A, meet(A, B)) + // 6- meet(B, meet(A, B)) + // 7- join(A, meet(A, B)) + // 8- join(B, meet(A, B)) + // 9- meet(A, join(A, B)) + // 10- meet(B, join(A, B)) + // 11- join(A, join(A, B)) + // 12- join(B, join(A, B)) // // In addition the meet of A[] and B[] requires the computation of the meet of A and B. // // The meet of A[] and B[] triggers the computation of: - // 1- meet(A[], B[][) - // 1.1- meet(A, B) - // 1.2- meet(B, A) - // 1.3- meet(dual(meet(A, B)), dual(A)) - // 1.4- meet(dual(meet(A, B)), dual(B)) - // 1.5- meet(dual(A), dual(B)) - // 1.6- meet(dual(B), dual(A)) - // 1.7- meet(dual(meet(dual(A), dual(B))), A) - // 1.8- meet(dual(meet(dual(A), dual(B))), B) + // 1- meet(A[], B[]) + // 1.1- meet(A, B) + // 1.2- meet(B, A) + // 1.3- join(A, B) + // 1.4- join(B, A) + // 1.5- meet(A, meet(A, B)) + // 1.6- meet(B, meet(A, B)) + // 1.7- join(A, meet(A, B)) + // 1.8- join(B, meet(A, B)) + // 1.9- meet(A, join(A, B)) + // 1.10- meet(B, join(A, B)) + // 1.11- join(A, join(A, B)) + // 1.12- join(B, join(A, B)) // 2- meet(B[], A[]) - // 2.1- meet(B, A) = 1.2 - // 2.2- meet(A, B) = 1.1 - // 2.3- meet(dual(meet(B, A)), dual(B)) = 1.4 - // 2.4- meet(dual(meet(B, A)), dual(A)) = 1.3 - // 2.5- meet(dual(B), dual(A)) = 1.6 - // 2.6- meet(dual(A), dual(B)) = 1.5 - // 2.7- meet(dual(meet(dual(B), dual(A))), B) = 1.8 - // 2.8- meet(dual(meet(dual(B), dual(A))), B) = 1.7 + // 2.1- meet(B, A) = 1.2 + // 2.2- meet(A, B) = 1.1 + // 2.3- join(B, A) = 1.4 + // 2.4- join(A, B) = 1.3 + // 2.5- meet(B, meet(B, A)) = 1.6 + // 2.6- meet(A, meet(B, A)) = 1.5 + // 2.7- join(B, meet(B, A)) = 1.8 + // 2.8- join(A, meet(B, A)) = 1.7 + // 2.9- meet(B, join(B, A)) = 1.10 + // 2.10- meet(A, join(B, A)) = 1.9 + // 2.11- join(B, join(B, A)) = 1.12 + // 2.12- join(A, join(B, A)) = 1.11 // etc. - // The number of meet operations performed grows exponentially with the number of dimensions of the arrays but the number - // of different meet operations is linear in the number of dimensions. The function below caches meet results for the - // duration of the meet at the root of the recursive calls. // - const Type* meet(const Type* t1, const Type* t2) { + // When the dimensions of the arrays increase, the number of performed operations grows + // exponentially but the number of distinct operations grows linearly. The function below caches + // the results for the duration of the operation at the root of the recursive calls. + template + static const Type* meet_join(F op, GrowableArray& cache, const Type* t1, const Type* t2) { bool found = false; - const VerifyMeetResultEntry meet(t1, t2, nullptr); - int pos = _cache.find_sorted(meet, found); + const CacheEntry entry(t1, t2, nullptr); + int pos = cache.find_sorted(entry, found); const Type* res = nullptr; if (found) { - res = _cache.at(pos).res(); + res = cache.at(pos).res(); } else { - res = t1->xmeet(t2); - _cache.insert_sorted(VerifyMeetResultEntry(t1, t2, res)); + res = op(t1, t2); + cache.insert_sorted(CacheEntry(t1, t2, res)); found = false; - _cache.find_sorted(meet, found); + cache.find_sorted(entry, found); assert(found, "should be in table after it's added"); } return res; } - void add(const Type* t1, const Type* t2, const Type* res) { - _cache.insert_sorted(VerifyMeetResultEntry(t1, t2, res)); + const Type* meet(const Type* t1, const Type* t2) { + auto op = [](const Type* t1, const Type* t2) { + return Type::xmeet(t1, t2); + }; + return meet_join(op, _meet_cache, t1, t2); + } + + const Type* join(const Type* t1, const Type* t2) { + auto op = [](const Type* t1, const Type* t2) { + return Type::xjoin(t1, t2); + }; + return meet_join(op, _join_cache, t1, t2); } - bool empty_cache() const { - return _cache.length() == 0; + void empty_cache() { + _meet_cache.trunc_to(0); + _join_cache.trunc_to(0); } public: - VerifyMeetResult(Compile* C) : - _depth(0), _cache(C->comp_arena(), 2, 0, VerifyMeetResultEntry()) { + VerifyMeetJoinResult(Compile* C) : _depth(0), + _meet_cache(C->comp_arena(), 2, 0, CacheEntry()), + _join_cache(C->comp_arena(), 2, 0, CacheEntry()) { } }; -void Type::assert_type_verify_empty() const { - assert(Compile::current()->_type_verify == nullptr || Compile::current()->_type_verify->empty_cache(), "cache should have been discarded"); -} - -class VerifyMeet { +class VerifyMeetJoin { private: Compile* _C; public: - VerifyMeet(Compile* C) : _C(C) { + VerifyMeetJoin(Compile* C) : _C(C) { if (C->_type_verify == nullptr) { - C->_type_verify = new (C->comp_arena())VerifyMeetResult(C); + C->_type_verify = new (C->comp_arena())VerifyMeetJoinResult(C); } _C->_type_verify->_depth++; } - ~VerifyMeet() { + ~VerifyMeetJoin() { assert(_C->_type_verify->_depth != 0, ""); _C->_type_verify->_depth--; if (_C->_type_verify->_depth == 0) { - _C->_type_verify->_cache.trunc_to(0); + _C->_type_verify->empty_cache(); } } - const Type* meet(const Type* t1, const Type* t2) const { + const Type* meet(const Type* t1, const Type* t2) { return _C->_type_verify->meet(t1, t2); } - void add(const Type* t1, const Type* t2, const Type* res) const { - _C->_type_verify->add(t1, t2, res); + const Type* join(const Type* t1, const Type* t2) { + return _C->_type_verify->join(t1, t2); } }; -void Type::check_symmetrical(const Type* t, const Type* mt, const VerifyMeet& verify) const { - Compile* C = Compile::current(); - const Type* mt2 = verify.meet(t, this); - - // Verify that: - // this meet t == t meet this - if (mt != mt2) { - tty->print_cr("=== Meet Not Commutative ==="); - tty->print("t = "); t->dump(); tty->cr(); - tty->print("this = "); dump(); tty->cr(); - tty->print("t meet this = "); mt2->dump(); tty->cr(); - tty->print("this meet t = "); mt->dump(); tty->cr(); +void Type::check_fundamental_laws(const Type* t1, const Type* t2, VerifyMeetJoin& verify) { + const Type* mt1 = verify.meet(t1, t2); + const Type* mt2 = verify.meet(t2, t1); + if (mt1 != mt2) { + stringStream ss; + ss.print_cr("=== Meet Not Commutative ==="); + ss.print("t1 = "); t1->dump_on(&ss); ss.cr(); + ss.print("t2 = "); t2->dump_on(&ss); ss.cr(); + ss.print("t1 meets t2 = "); mt1->dump_on(&ss); ss.cr(); + ss.print("t2 meets t1 = "); mt2->dump_on(&ss); ss.cr(); + tty->print("%s", ss.as_string()); fatal("meet not commutative"); } - const Type* dual_join = mt->_dual; - const Type* t2t = verify.meet(dual_join,t->_dual); - const Type* t2this = verify.meet(dual_join,this->_dual); - - // Interface meet Oop is Not Symmetric: - // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull - // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull - - // Verify that: - // 1) mt_dual meet t_dual == t_dual - // which corresponds to - // !(t meet this) meet !t == - // (!t join !this) meet !t == !t - // 2) mt_dual meet this_dual == this_dual - // which corresponds to - // !(t meet this) meet !this == - // (!t join !this) meet !this == !this - if (t2t != t->_dual || t2this != this->_dual) { - tty->print_cr("=== Meet Not Symmetric ==="); - tty->print("t = "); t->dump(); tty->cr(); - tty->print("this= "); dump(); tty->cr(); - tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); - - tty->print("t_dual= "); t->_dual->dump(); tty->cr(); - tty->print("this_dual= "); _dual->dump(); tty->cr(); - tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); - - // 1) - tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); - // 2) - tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); - tty->cr(); - tty->print_cr("Fail: "); - if (t2t != t->_dual) { - tty->print_cr("- mt_dual meet t_dual != t_dual"); + + const Type* jt1 = verify.join(t1, t2); + const Type* jt2 = verify.join(t2, t1); + if (jt1 != jt2) { + stringStream ss; + ss.print_cr("=== Join Not Commutative ==="); + ss.print("t1 = "); t1->dump_on(&ss); ss.cr(); + ss.print("t2 = "); t2->dump_on(&ss); ss.cr(); + ss.print("t1 joins t2 = "); jt1->dump_on(&ss); ss.cr(); + ss.print("t2 joins t1 = "); jt2->dump_on(&ss); ss.cr(); + tty->print("%s", ss.as_string()); + fatal("join not commutative"); + } + + const Type* mt = mt1; + const Type* jt = jt1; + + const Type* t1mmt = verify.meet(t1, mt); + const Type* t2mmt = verify.meet(t2, mt); + const Type* t1jmt = verify.join(t1, mt); + const Type* t2jmt = verify.join(t2, mt); + const Type* t1mjt = verify.meet(t1, jt); + const Type* t2mjt = verify.meet(t2, jt); + const Type* t1jjt = verify.join(t1, jt); + const Type* t2jjt = verify.join(t2, jt); + + if (t1mmt != mt || t2mmt != mt || t1jmt != t1 || t2jmt != t2 || + t1mjt != t1 || t2mjt != t2 || t1jjt != jt || t2jjt != jt) { + stringStream ss; + ss.print_cr("=== Fundamental Laws Violation ==="); + ss.print("t1 = "); t1->dump_on(&ss); ss.cr(); + ss.print("t2 = "); t2->dump_on(&ss); ss.cr(); + ss.print("mt = t1 meets t2 = "); mt->dump_on(&ss); ss.cr(); + ss.print("jt = t1 joins t2 = "); jt->dump_on(&ss); ss.cr(); + + ss.print("t1 meets mt = "); t1mmt->dump_on(&ss); ss.cr(); + ss.print("t2 meets mt = "); t2mmt->dump_on(&ss); ss.cr(); + ss.print("t1 joins mt = "); t1jmt->dump_on(&ss); ss.cr(); + ss.print("t2 joins mt = "); t2jmt->dump_on(&ss); ss.cr(); + ss.print("t1 meets jt = "); t1mjt->dump_on(&ss); ss.cr(); + ss.print("t2 meets jt = "); t2mjt->dump_on(&ss); ss.cr(); + ss.print("t1 joins jt = "); t1jjt->dump_on(&ss); ss.cr(); + ss.print("t2 joins jt = "); t2jjt->dump_on(&ss); ss.cr(); + ss.cr(); + + ss.print_cr("Failed laws:"); + if (t1mmt != mt) { + ss.print_cr("t1 meets mt == mt"); + } + if (t2mmt != mt) { + ss.print_cr("t2 meets mt == mt"); } - if (t2this != this->_dual) { - tty->print_cr("- mt_dual meet this_dual != this_dual"); + if (t1jmt != t1) { + ss.print_cr("t1 joins mt == t1"); + } + if (t2jmt != t2) { + ss.print_cr("t2 joins mt == t2"); + } + if (t1mjt != t1) { + ss.print_cr("t1 meets jt == t1"); + } + if (t2mjt != t2) { + ss.print_cr("t2 meets jt == t2"); + } + if (t1jjt != jt) { + ss.print_cr("t1 joins jt == jt"); + } + if (t2jjt != jt) { + ss.print_cr("t2 joins jt == jt"); } - tty->cr(); - fatal("meet not symmetric"); + tty->print("%s", ss.as_string()); + fatal("Fundamental Laws Violation"); } } #endif -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. NOT virtual. It enforces that meet is -// commutative and the lattice is symmetric. -const Type *Type::meet_helper(const Type *t, bool include_speculative) const { - if (isa_narrowoop() && t->isa_narrowoop()) { - const Type* result = make_ptr()->meet_helper(t->make_ptr(), include_speculative); +template +const Type* Type::meet_join_helper(F op, const Type* t1, const Type* t2, bool include_speculative) { + if (t1->isa_narrowoop() && t2->isa_narrowoop()) { + const Type* result = meet_join_helper(op, t1->make_ptr(), t2->make_ptr(), include_speculative); return result->make_narrowoop(); } - if (isa_narrowklass() && t->isa_narrowklass()) { - const Type* result = make_ptr()->meet_helper(t->make_ptr(), include_speculative); + if (t1->isa_narrowklass() && t2->isa_narrowklass()) { + const Type* result = meet_join_helper(op, t1->make_ptr(), t2->make_ptr(), include_speculative); return result->make_narrowklass(); } + t1 = t1->maybe_remove_speculative(include_speculative); + t2 = t2->maybe_remove_speculative(include_speculative); + const Type* rt = op(t1, t2); + #ifdef ASSERT Compile* C = Compile::current(); - VerifyMeet verify(C); + VerifyMeetJoin verify(C); + check_fundamental_laws(t1, t2, verify); #endif - const Type *this_t = maybe_remove_speculative(include_speculative); - t = t->maybe_remove_speculative(include_speculative); - - const Type *mt = this_t->xmeet(t); -#ifdef ASSERT - verify.add(this_t, t, mt); - if (isa_narrowoop() || t->isa_narrowoop()) { - return mt; - } - if (isa_narrowklass() || t->isa_narrowklass()) { - return mt; - } - // TODO 8387653 This currently triggers a verification failure, the code around "// Even though MyValue is final" needs adjustments - if ((this_t->isa_ptr() && this_t->is_ptr()->is_not_flat()) || - (this_t->_dual->isa_ptr() && this_t->_dual->is_ptr()->is_not_flat())) return mt; - this_t->check_symmetrical(t, mt, verify); - const Type *mt_dual = verify.meet(this_t->_dual, t->_dual); - this_t->_dual->check_symmetrical(t->_dual, mt_dual, verify); -#endif - return mt; + return rt; } -//------------------------------xmeet------------------------------------------ -// Compute the MEET of two types. It returns a new Type object. -const Type *Type::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Meeting TOP with anything? - if( _base == Top ) return t; - - // Meeting BOTTOM with anything? - if( _base == Bottom ) return BOTTOM; +// These methods compute the meet and join of two types. They perform additional verification that +// ensures the sanity of the implementation. +const Type* Type::meet_helper(const Type* t, bool include_speculative) const { + auto op = [](const Type* t1, const Type* t2) { + return xmeet(t1, t2); + }; + return meet_join_helper(op, this, t, include_speculative); +} - // Current "this->_base" is one of: Bad, Multi, Control, Top, - // Abio, Abstore, Floatxxx, Doublexxx, Bottom, lastype. - switch (t->base()) { // Switch on original type +const Type* Type::join_helper(const Type* t, bool include_speculative) const { + auto op = [](const Type* t1, const Type* t2) { + return xjoin(t1, t2); + }; + return meet_join_helper(op, this, t, include_speculative); +} - // Cut in half the number of cases I must handle. Only need cases for when - // the given enum "t->type" is less than or equal to the local enum "type". - case HalfFloatCon: - case FloatCon: - case DoubleCon: - case Int: - case Long: - return t->xmeet(this); +const Type* Type::xmeet(const Type* t1, const Type* t2) { + if (t1 == t2) { + return t1; + } + if (t1 == Type::TOP) { + return t2; + } else if (t2 == Type::TOP) { + return t1; + } else if (t1 == Type::BOTTOM || t2 == Type::BOTTOM) { + return Type::BOTTOM; + } - case OopPtr: - return t->xmeet(this); + return t1->xmeet(t2); +} - case InstPtr: - return t->xmeet(this); +const Type* Type::xjoin(const Type* t1, const Type* t2) { + if (t1 == t2) { + return t1; + } + if (t1 == Type::TOP || t2 == Type::TOP) { + return Type::TOP; + } else if (t1 == Type::BOTTOM) { + return t2; + } else if (t2 == Type::BOTTOM) { + return t1; + } - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - return t->xmeet(this); + return t1->xjoin(t2); +} - case AryPtr: - return t->xmeet(this); +//------------------------------xmeet------------------------------------------ +// Compute the MEET of two types. It returns a new Type object. +const Type* Type::xmeet(const Type* t) const { + // Current "this->_base" is one of: Floatxxx, Doublexxx. For Bad, Multi, Control, Abio, Abstore, + // should have been handled by Type::xmeet(const Type* t1, const Type* t2) since their types are + // singleton and t1 must always be equal to t2. + switch (base()) { + default: + typerr(t); + + case HalfFloatTop: + case HalfFloatBot: + case FloatTop: + case FloatBot: + case DoubleTop: + case DoubleBot: + break; + } - case NarrowOop: - return t->xmeet(this); + switch (t->base()) { // Switch on original type + case HalfFloatCon: + case FloatCon: + case DoubleCon: + return t->xmeet(this); + + case HalfFloatTop: + if (base() == HalfFloatTop || base() == HalfFloatBot) { + return this; + } + typerr(t); + case HalfFloatBot: + if (base() == HalfFloatTop || base() == HalfFloatBot) { + return t; + } + typerr(t); - case NarrowKlass: - return t->xmeet(this); + case FloatTop: + if (base() == FloatTop || base() == FloatBot) { + return this; + } + typerr(t); + case FloatBot: + if (base() == FloatTop || base() == FloatBot) { + return t; + } + typerr(t); - case Bad: // Type check - default: // Bogus type not in lattice - typerr(t); - return Type::BOTTOM; + case DoubleTop: + if (base() == DoubleTop || base() == DoubleBot) { + return this; + } + typerr(t); + case DoubleBot: + if (base() == DoubleTop || base() == DoubleBot) { + return t; + } + typerr(t); - case Bottom: // Ye Olde Default - return t; + default: + typerr(t); + } +} - case HalfFloatTop: - if (_base == HalfFloatTop) { return this; } - case HalfFloatBot: // Half Float - if (_base == HalfFloatBot || _base == HalfFloatTop) { return HALF_FLOAT; } - if (_base == FloatBot || _base == FloatTop) { return Type::BOTTOM; } - if (_base == DoubleTop || _base == DoubleBot) { return Type::BOTTOM; } - typerr(t); - return Type::BOTTOM; +// Compute the JOIN of two types. This is similar to xmeet above. +const Type* Type::xjoin(const Type* t) const { + switch (base()) { + default: + typerr(t); + + case HalfFloatTop: + case HalfFloatBot: + case FloatTop: + case FloatBot: + case DoubleTop: + case DoubleBot: + break; + } - case FloatTop: - if (_base == FloatTop ) { return this; } - case FloatBot: // Float - if (_base == FloatBot || _base == FloatTop) { return FLOAT; } - if (_base == HalfFloatTop || _base == HalfFloatBot) { return Type::BOTTOM; } - if (_base == DoubleTop || _base == DoubleBot) { return Type::BOTTOM; } - typerr(t); - return Type::BOTTOM; + switch (t->base()) { // Switch on original type + case HalfFloatCon: + case FloatCon: + case DoubleCon: + return t->xjoin(this); + + case HalfFloatTop: + if (base() == HalfFloatTop || base() == HalfFloatBot) { + return t; + } + typerr(t); + case HalfFloatBot: + if (base() == HalfFloatTop || base() == HalfFloatBot) { + return this; + } + typerr(t); - case DoubleTop: - if (_base == DoubleTop) { return this; } - case DoubleBot: // Double - if (_base == DoubleBot || _base == DoubleTop) { return DOUBLE; } - if (_base == HalfFloatTop || _base == HalfFloatBot) { return Type::BOTTOM; } - if (_base == FloatTop || _base == FloatBot) { return Type::BOTTOM; } - typerr(t); - return Type::BOTTOM; + case FloatTop: + if (base() == FloatTop || base() == FloatBot) { + return t; + } + typerr(t); + case FloatBot: + if (base() == FloatTop || base() == FloatBot) { + return this; + } + typerr(t); - // These next few cases must match exactly or it is a compile-time error. - case Control: // Control of code - case Abio: // State of world outside of program - case Memory: - if (_base == t->_base) { return this; } - typerr(t); - return Type::BOTTOM; + case DoubleTop: + if (base() == DoubleTop || base() == DoubleBot) { + return t; + } + typerr(t); + case DoubleBot: + if (base() == DoubleTop || base() == DoubleBot) { + return this; + } + typerr(t); - case Top: // Top of the lattice - return this; + default: + typerr(t); } - - // The type is unchanged - return this; } //-----------------------------filter------------------------------------------ @@ -1266,13 +1356,6 @@ const Type *Type::filter_helper(const Type *kills, bool include_speculative) con return ft; } -//------------------------------xdual------------------------------------------ -const Type *Type::xdual() const { - // Note: the base() accessor asserts the sanity of _base. - assert(_type_info[base()].dual_type != Bad, "implement with v-call"); - return new Type(_type_info[_base].dual_type); -} - //------------------------------has_memory------------------------------------- bool Type::has_memory() const { Type::TYPES tx = base(); @@ -1470,59 +1553,34 @@ const TypeF *TypeF::make(float f) { return (TypeF*)(new TypeF(f))->hashcons(); } -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeF::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - +const Type* TypeF::xmeet(const Type* t) const { // Current "this->_base" is FloatCon - switch (t->base()) { // Switch on original type - case AnyPtr: // Mixing with oops happens when javac - case RawPtr: // reuses local variables - case OopPtr: - case InstPtr: - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case NarrowOop: - case NarrowKlass: - case Int: - case Long: - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - - case FloatBot: - return t; - - default: // All else is a mistake - typerr(t); - - case FloatCon: // Float-constant vs Float-constant? - if( jint_cast(_f) != jint_cast(t->getf()) ) // unequal constants? - // must compare bitwise as positive zero, negative zero and NaN have - // all the same representation in C++ - return FLOAT; // Return generic float - // Equal constants - case Top: - case FloatTop: - break; // Return the float constant + switch (t->base()) { + case FloatTop: + return this; + case FloatCon: + assert(jint_cast(_f) != jint_cast(t->getf()), "Equivalent instances should not appear here"); + return Type::FLOAT; + case FloatBot: + return t; + default: + typerr(t); } - return this; // Return the float constant } -//------------------------------xdual------------------------------------------ -// Dual: symmetric -const Type *TypeF::xdual() const { - return this; +const Type* TypeF::xjoin(const Type* t) const { + // Current "this->_base" is FloatCon + switch (t->base()) { + case FloatTop: + return t; + case FloatCon: + assert(jint_cast(_f) != jint_cast(t->getf()), "Equivalent instances should not appear here"); + return Type::make(FloatTop); + case FloatBot: + return this; + default: + typerr(t); + } } //------------------------------eq--------------------------------------------- @@ -1593,59 +1651,34 @@ const TypeH* TypeH::make(float f) { return (TypeH*)(new TypeH(hf))->hashcons(); } -//------------------------------xmeet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. const Type* TypeH::xmeet(const Type* t) const { - // Perform a fast test for common case; meeting the same types together. - if (this == t) return this; // Meeting same type-rep? - // Current "this->_base" is FloatCon - switch (t->base()) { // Switch on original type - case AnyPtr: // Mixing with oops happens when javac - case RawPtr: // reuses local variables - case OopPtr: - case InstPtr: - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case NarrowOop: - case NarrowKlass: - case Int: - case Long: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - - case HalfFloatBot: - return t; - - default: // All else is a mistake - typerr(t); - - case HalfFloatCon: // Half float-constant vs Half float-constant? - if (_f != t->geth()) { // unequal constants? - // must compare bitwise as positive zero, negative zero and NaN have - // all the same representation in C++ - return HALF_FLOAT; // Return generic float - } // Equal constants - case Top: - case HalfFloatTop: - break; // Return the Half float constant + switch (t->base()) { + case HalfFloatTop: + return this; + case HalfFloatCon: + assert(_f != t->is_half_float_constant()->_f, "Equivalent instances should not appear here"); + return Type::HALF_FLOAT; + case HalfFloatBot: + return t; + default: + typerr(t); } - return this; // Return the Half float constant } -//------------------------------xdual------------------------------------------ -// Dual: symmetric -const Type* TypeH::xdual() const { - return this; +const Type* TypeH::xjoin(const Type* t) const { + // Current "this->_base" is FloatCon + switch (t->base()) { + case HalfFloatTop: + return t; + case HalfFloatCon: + assert(_f != t->is_half_float_constant()->_f, "Equivalent instances should not appear here"); + return Type::make(HalfFloatTop); + case HalfFloatBot: + return this; + default: + typerr(t); + } } //------------------------------eq--------------------------------------------- @@ -1718,56 +1751,34 @@ const TypeD *TypeD::make(double d) { return (TypeD*)(new TypeD(d))->hashcons(); } -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeD::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - +const Type* TypeD::xmeet(const Type* t) const { // Current "this->_base" is DoubleCon - switch (t->base()) { // Switch on original type - case AnyPtr: // Mixing with oops happens when javac - case RawPtr: // reuses local variables - case OopPtr: - case InstPtr: - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case NarrowOop: - case NarrowKlass: - case Int: - case Long: - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - - case DoubleBot: - return t; - - default: // All else is a mistake - typerr(t); - - case DoubleCon: // Double-constant vs Double-constant? - if( jlong_cast(_d) != jlong_cast(t->getd()) ) // unequal constants? (see comment in TypeF::xmeet) - return DOUBLE; // Return generic double - case Top: - case DoubleTop: - break; + switch (t->base()) { + case DoubleTop: + return this; + case DoubleCon: + assert(jlong_cast(_d) != jlong_cast(t->getd()), "Equivalent instances should not appear here"); + return Type::DOUBLE; + case DoubleBot: + return t; + default: + typerr(t); } - return this; // Return the double constant } -//------------------------------xdual------------------------------------------ -// Dual: symmetric -const Type *TypeD::xdual() const { - return this; +const Type* TypeD::xjoin(const Type* t) const { + // Current "this->_base" is DoubleCon + switch (t->base()) { + case DoubleTop: + return t; + case DoubleCon: + assert(jlong_cast(_d) != jlong_cast(t->getd()), "Equivalent instances should not appear here"); + return Type::make(DoubleTop); + case DoubleBot: + return this; + default: + typerr(t); + } } //------------------------------eq--------------------------------------------- @@ -1895,24 +1906,16 @@ const TypeInt* TypeInt::INT; // 32-bit integers const TypeInt* TypeInt::SYMINT; // symmetric range [-max_jint..max_jint] const TypeInt* TypeInt::TYPE_DOMAIN; // alias for TypeInt::INT -TypeInt::TypeInt(const TypeIntPrototype& t, int widen, bool dual) - : TypeInteger(Int, t.normalize_widen(widen), dual), _lo(t._srange._lo), _hi(t._srange._hi), +TypeInt::TypeInt(const TypeIntPrototype& t, int widen) + : TypeInteger(Int, t.normalize_widen(widen)), _lo(t._srange._lo), _hi(t._srange._hi), _ulo(t._urange._lo), _uhi(t._urange._hi), _bits(t._bits) { DEBUG_ONLY(t.verify_constraints()); } -const Type* TypeInt::make_or_top(const TypeIntPrototype& t, int widen, bool dual) { - auto canonicalized_t = t.canonicalize_constraints(); - if (canonicalized_t.empty()) { - return dual ? Type::BOTTOM : Type::TOP; - } - return (new TypeInt(canonicalized_t._data, widen, dual))->hashcons()->is_int(); -} - const TypeInt* TypeInt::make(jint con) { juint ucon = con; return (new TypeInt(TypeIntPrototype{{con, con}, {ucon, ucon}, {~ucon, ucon}}, - WidenMin, false))->hashcons()->is_int(); + WidenMin))->hashcons()->is_int(); } const TypeInt* TypeInt::make(jint lo, jint hi, int widen) { @@ -1927,11 +1930,14 @@ const TypeInt* TypeInt::make_unsigned(juint ulo, juint uhi, int widen) { } const Type* TypeInt::make_or_top(const TypeIntPrototype& t, int widen) { - return make_or_top(t, widen, false); + auto canonicalized_t = t.canonicalize_constraints(); + if (canonicalized_t.empty()) { + return Type::TOP; + } + return (new TypeInt(canonicalized_t._data, widen))->hashcons()->is_int(); } bool TypeInt::contains(jint i) const { - assert(!_is_dual, "dual types should only be used for join calculation"); juint u = i; return i >= _lo && i <= _hi && u >= _ulo && u <= _uhi && @@ -1939,33 +1945,34 @@ bool TypeInt::contains(jint i) const { } bool TypeInt::contains(const TypeInt* t) const { - assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_is_subset(this, t); } #ifdef ASSERT bool TypeInt::strictly_contains(const TypeInt* t) const { - assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_is_subset(this, t) && !TypeIntHelper::int_type_is_equal(this, t); } #endif // ASSERT const Type* TypeInt::xmeet(const Type* t) const { - return TypeIntHelper::int_type_xmeet(this, t); + if (base() != Int || t->base() != Int) { + typerr(t); + } + return TypeIntHelper::int_type_xmeet(this, t->is_int()); } -const Type* TypeInt::xdual() const { - return new TypeInt(TypeIntPrototype{{_lo, _hi}, {_ulo, _uhi}, _bits}, - _widen, !_is_dual); +const Type* TypeInt::xjoin(const Type* t) const { + if (base() != Int || t->base() != Int) { + typerr(t); + } + return TypeIntHelper::int_type_xjoin(this, t->is_int()); } const Type* TypeInt::widen(const Type* old, const Type* limit) const { - assert(!_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_widen(this, old->isa_int(), limit->isa_int()); } const Type* TypeInt::narrow(const Type* old) const { - assert(!_is_dual, "dual types should only be used for join calculation"); if (old == nullptr) { return this; } @@ -1975,17 +1982,15 @@ const Type* TypeInt::narrow(const Type* old) const { //-----------------------------filter------------------------------------------ const Type* TypeInt::filter_helper(const Type* kills, bool include_speculative) const { - assert(!_is_dual, "dual types should only be used for join calculation"); const TypeInt* ft = join_helper(kills, include_speculative)->isa_int(); if (ft == nullptr) { return Type::TOP; // Canonical empty value } - assert(!ft->_is_dual, "dual types should only be used for join calculation"); if (ft->_widen < this->_widen) { // Do not allow the value of kill->_widen to affect the outcome. // The widen bits must be allowed to run freely through the graph. return (new TypeInt(TypeIntPrototype{{ft->_lo, ft->_hi}, {ft->_ulo, ft->_uhi}, ft->_bits}, - this->_widen, false))->hashcons(); + this->_widen))->hashcons(); } return ft; } @@ -1994,14 +1999,14 @@ const Type* TypeInt::filter_helper(const Type* kills, bool include_speculative) // Structural equality check for Type representations bool TypeInt::eq(const Type* t) const { const TypeInt* r = t->is_int(); - return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen && _is_dual == r->_is_dual; + return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen; } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeInt::hash(void) const { return (uint)_lo + (uint)_hi + (uint)_ulo + (uint)_uhi + - (uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)_is_dual + (uint)Type::Int; + (uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)Type::Int; } //------------------------------is_finite-------------------------------------- @@ -2036,24 +2041,16 @@ const TypeLong* TypeLong::INT; // 32-bit subrange const TypeLong* TypeLong::UINT; // 32-bit unsigned subrange const TypeLong* TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG -TypeLong::TypeLong(const TypeIntPrototype& t, int widen, bool dual) - : TypeInteger(Long, t.normalize_widen(widen), dual), _lo(t._srange._lo), _hi(t._srange._hi), +TypeLong::TypeLong(const TypeIntPrototype& t, int widen) + : TypeInteger(Long, t.normalize_widen(widen)), _lo(t._srange._lo), _hi(t._srange._hi), _ulo(t._urange._lo), _uhi(t._urange._hi), _bits(t._bits) { DEBUG_ONLY(t.verify_constraints()); } -const Type* TypeLong::make_or_top(const TypeIntPrototype& t, int widen, bool dual) { - auto canonicalized_t = t.canonicalize_constraints(); - if (canonicalized_t.empty()) { - return dual ? Type::BOTTOM : Type::TOP; - } - return (new TypeLong(canonicalized_t._data, widen, dual))->hashcons()->is_long(); -} - const TypeLong* TypeLong::make(jlong con) { julong ucon = con; return (new TypeLong(TypeIntPrototype{{con, con}, {ucon, ucon}, {~ucon, ucon}}, - WidenMin, false))->hashcons()->is_long(); + WidenMin))->hashcons()->is_long(); } const TypeLong* TypeLong::make(jlong lo, jlong hi, int widen) { @@ -2068,11 +2065,14 @@ const TypeLong* TypeLong::make_unsigned(julong ulo, julong uhi, int widen) { } const Type* TypeLong::make_or_top(const TypeIntPrototype& t, int widen) { - return make_or_top(t, widen, false); + auto canonicalized_t = t.canonicalize_constraints(); + if (canonicalized_t.empty()) { + return Type::TOP; + } + return (new TypeLong(canonicalized_t._data, widen))->hashcons()->is_long(); } bool TypeLong::contains(jlong i) const { - assert(!_is_dual, "dual types should only be used for join calculation"); julong u = i; return i >= _lo && i <= _hi && u >= _ulo && u <= _uhi && @@ -2080,33 +2080,34 @@ bool TypeLong::contains(jlong i) const { } bool TypeLong::contains(const TypeLong* t) const { - assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_is_subset(this, t); } #ifdef ASSERT bool TypeLong::strictly_contains(const TypeLong* t) const { - assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_is_subset(this, t) && !TypeIntHelper::int_type_is_equal(this, t); } #endif // ASSERT const Type* TypeLong::xmeet(const Type* t) const { - return TypeIntHelper::int_type_xmeet(this, t); + if (base() != Long || t->base() != Long) { + typerr(t); + } + return TypeIntHelper::int_type_xmeet(this, t->is_long()); } -const Type* TypeLong::xdual() const { - return new TypeLong(TypeIntPrototype{{_lo, _hi}, {_ulo, _uhi}, _bits}, - _widen, !_is_dual); +const Type* TypeLong::xjoin(const Type* t) const { + if (base() != Long || t->base() != Long) { + typerr(t); + } + return TypeIntHelper::int_type_xjoin(this, t->is_long()); } const Type* TypeLong::widen(const Type* old, const Type* limit) const { - assert(!_is_dual, "dual types should only be used for join calculation"); return TypeIntHelper::int_type_widen(this, old->isa_long(), limit->isa_long()); } const Type* TypeLong::narrow(const Type* old) const { - assert(!_is_dual, "dual types should only be used for join calculation"); if (old == nullptr) { return this; } @@ -2116,17 +2117,15 @@ const Type* TypeLong::narrow(const Type* old) const { //-----------------------------filter------------------------------------------ const Type* TypeLong::filter_helper(const Type* kills, bool include_speculative) const { - assert(!_is_dual, "dual types should only be used for join calculation"); const TypeLong* ft = join_helper(kills, include_speculative)->isa_long(); if (ft == nullptr) { return Type::TOP; // Canonical empty value } - assert(!ft->_is_dual, "dual types should only be used for join calculation"); if (ft->_widen < this->_widen) { // Do not allow the value of kill->_widen to affect the outcome. // The widen bits must be allowed to run freely through the graph. return (new TypeLong(TypeIntPrototype{{ft->_lo, ft->_hi}, {ft->_ulo, ft->_uhi}, ft->_bits}, - this->_widen, false))->hashcons(); + this->_widen))->hashcons(); } return ft; } @@ -2135,14 +2134,14 @@ const Type* TypeLong::filter_helper(const Type* kills, bool include_speculative) // Structural equality check for Type representations bool TypeLong::eq(const Type* t) const { const TypeLong* r = t->is_long(); - return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen && _is_dual == r->_is_dual; + return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen; } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeLong::hash(void) const { return (uint)_lo + (uint)_hi + (uint)_ulo + (uint)_uhi + - (uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)_is_dual + (uint)Type::Long; + (uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)Type::Long; } //------------------------------is_finite-------------------------------------- @@ -2360,40 +2359,24 @@ const Type **TypeTuple::fields( uint arg_cnt ) { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeTuple::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Current "this->_base" is Tuple - switch (t->base()) { // switch on original type - - case Bottom: // Ye Olde Default - return t; - - default: // All else is a mistake - typerr(t); - - case Tuple: { // Meeting 2 signatures? - const TypeTuple *x = t->is_tuple(); - assert( _cnt == x->_cnt, "" ); - const Type **fields = (const Type **)(Compile::current()->type_arena()->AmallocWords( _cnt*sizeof(Type*) )); - for( uint i=0; i<_cnt; i++ ) - fields[i] = field_at(i)->xmeet( x->field_at(i) ); - return TypeTuple::make(_cnt,fields); +const Type* TypeTuple::xmeet(const Type* t) const { + const TypeTuple* x = t->is_tuple(); + assert(_cnt == x->_cnt, "mismatched shape: %d != %d", _cnt, x->_cnt); + const Type** fields = static_cast(Compile::current()->type_arena()->AmallocWords(_cnt * sizeof(Type*))); + for (uint i = 0; i < _cnt; i++) { + fields[i] = field_at(i)->meet_speculative(x->field_at(i)); } - case Top: - break; - } - return this; // Return the double constant + return TypeTuple::make(_cnt, fields); } -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeTuple::xdual() const { - const Type **fields = (const Type **)(Compile::current()->type_arena()->AmallocWords( _cnt*sizeof(Type*) )); - for( uint i=0; i<_cnt; i++ ) - fields[i] = _fields[i]->dual(); - return new TypeTuple(_cnt,fields); +const Type* TypeTuple::xjoin(const Type* t) const { + const TypeTuple* x = t->is_tuple(); + assert(_cnt == x->_cnt, "mismatched shape: %d != %d", _cnt, x->_cnt); + const Type** fields = static_cast(Compile::current()->type_arena()->AmallocWords(_cnt * sizeof(Type*))); + for (uint i = 0; i < _cnt; i++) { + fields[i] = field_at(i)->join_speculative(x->field_at(i)); + } + return TypeTuple::make(_cnt, fields); } //------------------------------eq--------------------------------------------- @@ -2471,56 +2454,12 @@ inline const TypeInt* normalize_array_size(const TypeInt* size) { //------------------------------make------------------------------------------- const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable, - bool flat, bool not_flat, bool not_null_free, bool atomic) { + bool flat, bool not_flat, bool null_free, bool not_null_free, bool atomic) { if (UseCompressedOops && elem->isa_oopptr()) { elem = elem->make_narrowoop(); } size = normalize_array_size(size); - return (TypeAry*)(new TypeAry(elem, size, stable, flat, not_flat, not_null_free, atomic))->hashcons(); -} - -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeAry::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Current "this->_base" is Ary - switch (t->base()) { // switch on original type - - case Bottom: // Ye Olde Default - return t; - - default: // All else is a mistake - typerr(t); - - case Array: { // Meeting 2 arrays? - const TypeAry* a = t->is_ary(); - const Type* size = _size->xmeet(a->_size); - const TypeInt* isize = size->isa_int(); - if (isize == nullptr) { - assert(size == Type::TOP || size == Type::BOTTOM, ""); - return size; - } - return TypeAry::make(_elem->meet_speculative(a->_elem), - isize, _stable && a->_stable, - _flat && a->_flat, - _not_flat && a->_not_flat, - _not_null_free && a->_not_null_free, - _atomic && a->_atomic); - } - case Top: - break; - } - return this; // Return the double constant -} - -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeAry::xdual() const { - const TypeInt* size_dual = _size->dual()->is_int(); - size_dual = normalize_array_size(size_dual); - return new TypeAry(_elem->dual(), size_dual, !_stable, !_flat, !_not_flat, !_not_null_free, !_atomic); + return (TypeAry*)(new TypeAry(elem, size, stable, flat, not_flat, null_free, not_null_free, atomic))->hashcons(); } //------------------------------eq--------------------------------------------- @@ -2532,6 +2471,7 @@ bool TypeAry::eq( const Type *t ) const { _size == a->_size && _flat == a->_flat && _not_flat == a->_not_flat && + _null_free == a->_null_free && _not_null_free == a->_not_null_free && _atomic == a->_atomic; @@ -2541,21 +2481,21 @@ bool TypeAry::eq( const Type *t ) const { // Type-specific hashing function. uint TypeAry::hash(void) const { return (uint)(uintptr_t)_elem + (uint)(uintptr_t)_size + (uint)(_stable ? 43 : 0) + - (uint)(_flat ? 44 : 0) + (uint)(_not_flat ? 45 : 0) + (uint)(_not_null_free ? 46 : 0) + (uint)(_atomic ? 47 : 0); + (uint)(_flat ? 44 : 0) + (uint)(_not_flat ? 45 : 0) + (uint)(_null_free ? 46 : 0) + (uint)(_not_null_free ? 47 : 0) + (uint)(_atomic ? 48 : 0); } /** * Return same type without a speculative part in the element */ const TypeAry* TypeAry::remove_speculative() const { - return make(_elem->remove_speculative(), _size, _stable, _flat, _not_flat, _not_null_free, _atomic); + return make(_elem->remove_speculative(), _size, _stable, _flat, _not_flat, _null_free, _not_null_free, _atomic); } /** * Return same type with cleaned up speculative part of element */ const Type* TypeAry::cleanup_speculative() const { - return make(_elem->cleanup_speculative(), _size, _stable, _flat, _not_flat, _not_null_free, _atomic); + return make(_elem->cleanup_speculative(), _size, _stable, _flat, _not_flat, _null_free, _not_null_free, _atomic); } /** @@ -2597,15 +2537,7 @@ bool TypeAry::singleton(void) const { bool TypeAry::empty(void) const { assert(!_size->empty(), "TypeInt is never empty"); - // TODO 8385426 This should be simplified at construction time once we get rid of dual - // Doing it with the dual-based join is annoying. TypeAry::empty tests whether the - // element type is empty. When computing the dual of an array that can be flat or not, - // we will get an element type that is empty, and doesn't need more. We even shouldn't - // do more otherwise, we can't make the dual involutive. But if we compute the - // intersection of a flat and a non-flat array, we could change the element type to an - // empty type to reduce the abstract value. And we must be careful not to do that in - // the dual world. - return _elem->empty() || (_flat && _not_flat); + return _elem->empty() || (_flat && _not_flat) || (_null_free && _not_null_free); } //--------------------------ary_must_be_exact---------------------------------- @@ -2613,41 +2545,39 @@ bool TypeAry::ary_must_be_exact() const { // This logic looks at the element type of an array, and returns true // if the element type is either a primitive or a final instance class. // In such cases, an array built on this ary must have no subclasses. - if (_elem == BOTTOM) return false; // general array not exact - if (_elem == TOP ) return false; // inverted general array not exact - const TypeOopPtr* toop = nullptr; - if (UseCompressedOops && _elem->isa_narrowoop()) { - toop = _elem->make_ptr()->isa_oopptr(); - } else { - toop = _elem->isa_oopptr(); + if (_elem == BOTTOM) { + // general array not exact + return false; + } else if (_elem == TOP) { + // inverted general array not exact + return false; } - if (!toop) return true; // a primitive type, like int - if (!toop->is_loaded()) return false; // unloaded class - const TypeInstPtr* tinst; - if (_elem->isa_narrowoop()) - tinst = _elem->make_ptr()->isa_instptr(); - else - tinst = _elem->isa_instptr(); - if (tinst) { - if (tinst->instance_klass()->is_final()) { - // Even though MyValue is final, [LMyValue is only exact if the array - // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue. - // TODO 8387653 If we know that the array can't be null-free, it's allowed to be exact, right? - // If so, we should add '&& !_not_null_free' - if (tinst->is_inlinetypeptr() && (tinst->ptr() != TypePtr::NotNull)) { - return false; - } + + const TypeOopPtr* toop = _elem->make_oopptr(); + if (toop == nullptr) { + // a primitive type, like int + return true; + } else if (!toop->is_loaded()) { + // unloaded class + return false; + } + + if (const TypeInstPtr* tinst = toop->isa_instptr(); tinst != nullptr) { + if (tinst->instance_klass()->is_final()) { + // Even though MyValue is final, MyValue[] is only exact if MyValue is not a value class, + // because there may be many refined type for MyValue[] + if (tinst->is_inlinetypeptr()) { + return false; + } return true; } return false; } - const TypeAryPtr* tap; - if (_elem->isa_narrowoop()) - tap = _elem->make_ptr()->isa_aryptr(); - else - tap = _elem->isa_aryptr(); - if (tap) + + if (const TypeAryPtr* tap = toop->isa_aryptr(); tap != nullptr) { return tap->ary()->ary_must_be_exact(); + } + return false; } @@ -2704,48 +2634,6 @@ const TypeVect* TypeVect::makemask(BasicType elem_bt, uint length) { } } -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. Since each TypeVect is the only instance of -// its species, meeting often returns itself -const Type* TypeVect::xmeet(const Type* t) const { - // Perform a fast test for common case; meeting the same types together. - if (this == t) { - return this; - } - - // Current "this->_base" is Vector - switch (t->base()) { // switch on original type - - case Bottom: // Ye Olde Default - return t; - - default: // All else is a mistake - typerr(t); - case VectorMask: - case VectorA: - case VectorS: - case VectorD: - case VectorX: - case VectorY: - case VectorZ: { // Meeting 2 vectors? - const TypeVect* v = t->is_vect(); - assert(base() == v->base(), ""); - assert(length() == v->length(), ""); - assert(element_basic_type() == v->element_basic_type(), ""); - return this; - } - case Top: - break; - } - return this; -} - -//------------------------------xdual------------------------------------------ -// Since each TypeVect is the only instance of its species, it is self-dual -const Type* TypeVect::xdual() const { - return this; -} - //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypeVect::eq(const Type* t) const { @@ -2864,50 +2752,82 @@ const Type *TypePtr::xmeet(const Type *t) const { return res; } -const Type *TypePtr::xmeet_helper(const Type *t) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? +const Type* TypePtr::xmeet_helper(const Type* t) const { + if (base() != AnyPtr) { + typerr(t); + } - // Current "this->_base" is AnyPtr - switch (t->base()) { // switch on original type - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); + return make(AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()), speculative, depth); + } + case RawPtr: + case OopPtr: + case InstPtr: + case AryPtr: + case MetadataPtr: + case KlassPtr: + case InstKlassPtr: + case AryKlassPtr: + // Call in reverse direction, delegate to the subtypes to implement the meet + return t->is_ptr()->xmeet(this); + default: + typerr(t); + } +} - case AnyPtr: { // Meeting to AnyPtrs - const TypePtr *tp = t->is_ptr(); - const TypePtr* speculative = xmeet_speculative(tp); - int depth = meet_inline_depth(tp->inline_depth()); - return make(AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()), speculative, depth); +const Type* TypePtr::xjoin(const Type* t) const { + const Type* res = xjoin_helper(t); + if (res->isa_ptr() == nullptr) { + return res; } - case RawPtr: // For these, flip the call around to cut down - case OopPtr: - case InstPtr: // on the cases I have to handle. - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - return t->xmeet(this); // Call in reverse direction - default: // All else is a mistake + + const TypePtr* res_ptr = res->is_ptr(); + if (res_ptr->speculative() != nullptr) { + // type->speculative() is null means that speculation is no better + // than type, i.e. type->speculative() == type. So there are 2 + // ways to represent the fact that we have no useful speculative + // data and we should use a single one to be able to test for + // equality between types. Check whether type->speculative() == + // type and set speculative to null if it is the case. + if (res_ptr->remove_speculative() == res_ptr->speculative()) { + return res_ptr->remove_speculative(); + } + } + + return res; +} + +const Type* TypePtr::xjoin_helper(const Type* t) const { + if (base() != AnyPtr) { typerr(t); + } + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + Offset offset = join_offset(tp->offset()); + PTR ptr = offset == Offset::top ? TopPTR : join_ptr(tp->ptr()); + const TypePtr* speculative = xjoin_speculative(tp); + int depth = join_inline_depth(tp->inline_depth()); + return make(AnyPtr, ptr, offset, speculative, depth); + } + case RawPtr: + case OopPtr: + case InstPtr: + case AryPtr: + case MetadataPtr: + case KlassPtr: + case InstKlassPtr: + case AryKlassPtr: + // Call in reverse direction + return t->is_ptr()->xjoin(this); + default: + typerr(t); } - return this; } //------------------------------meet_offset------------------------------------ @@ -2915,32 +2835,20 @@ Type::Offset TypePtr::meet_offset(int offset) const { return _offset.meet(Offset(offset)); } -//------------------------------dual_offset------------------------------------ -Type::Offset TypePtr::dual_offset() const { - return _offset.dual(); +Type::Offset TypePtr::join_offset(int offset) const { + return _offset.join(Offset(offset)); } +const char* const TypePtr::flat_in_array_msg[Uninitialized] = { + "TOP flat in array", "flat in array", "not flat in array", "maybe flat in array" +}; + //------------------------------xdual------------------------------------------ // Dual: compute field-by-field dual const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = { BotPTR, NotNull, Constant, Null, AnyNull, TopPTR }; -const TypePtr::FlatInArray TypePtr::flat_in_array_dual[Uninitialized] = { - /* TopFlat -> */ MaybeFlat, - /* Flat -> */ NotFlat, - /* NotFlat -> */ Flat, - /* MaybeFlat -> */ TopFlat -}; - -const char* const TypePtr::flat_in_array_msg[Uninitialized] = { - "TOP flat in array", "flat in array", "not flat in array", "maybe flat in array" -}; - -const Type *TypePtr::xdual() const { - return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), relocInfo::none, dual_speculative(), dual_inline_depth()); -} - //------------------------------xadd_offset------------------------------------ Type::Offset TypePtr::xadd_offset(intptr_t offset) const { return _offset.add(offset); @@ -3008,54 +2916,55 @@ const Type* TypePtr::cleanup_speculative() const { return this; } -/** - * dual of the speculative part of the type - */ -const TypePtr* TypePtr::dual_speculative() const { - if (_speculative == nullptr) { - return nullptr; - } - return _speculative->dual()->is_ptr(); -} - /** * meet of the speculative parts of 2 types * * @param other type to meet with */ const TypePtr* TypePtr::xmeet_speculative(const TypePtr* other) const { - bool this_has_spec = (_speculative != nullptr); - bool other_has_spec = (other->speculative() != nullptr); + bool this_no_spec = speculative() == nullptr; + bool other_no_spec = other->speculative() == nullptr; - if (!this_has_spec && !other_has_spec) { + if (this_no_spec && other_no_spec) { return nullptr; } - // If we are at a point where control flow meets and one branch has - // a speculative type and the other has not, we meet the speculative - // type of one branch with the actual type of the other. If the - // actual type is exact and the speculative is as well, then the - // result is a speculative type which is exact and we can continue - // speculation further. - const TypePtr* this_spec = _speculative; + // Use the static type if speculative() is nullptr + const TypePtr* this_spec = speculative(); const TypePtr* other_spec = other->speculative(); - if (!this_has_spec) { + if (this_no_spec) { this_spec = this; } - if (!other_has_spec) { + if (other_no_spec) { other_spec = other; } return this_spec->meet(other_spec)->is_ptr(); } -/** - * dual of the inline depth for this type (used for speculation) - */ -int TypePtr::dual_inline_depth() const { - return -inline_depth(); +const TypePtr* TypePtr::xjoin_speculative(const TypePtr* other) const { + bool this_no_spec = speculative() == nullptr; + bool other_no_spec = other->speculative() == nullptr; + + if (this_no_spec && other_no_spec) { + return nullptr; + } + + // Use the static type if speculative() is nullptr + const TypePtr* this_spec = speculative(); + const TypePtr* other_spec = other->speculative(); + + if (this_no_spec) { + this_spec = this; + } + + if (other_no_spec) { + other_spec = other; + } + + return this_spec->join(other_spec)->is_ptr(); } /** @@ -3067,6 +2976,10 @@ int TypePtr::meet_inline_depth(int depth) const { return MAX2(inline_depth(), depth); } +int TypePtr::join_inline_depth(int depth) const { + return MIN2(inline_depth(), depth); +} + /** * Are the speculative parts of 2 types equal? * @@ -3357,22 +3270,19 @@ intptr_t TypeRawPtr::get_con() const { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeRawPtr::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Current "this->_base" is RawPtr - switch( t->base() ) { // switch on original type - case Bottom: // Ye Olde Default - return t; - case Top: - return this; - case AnyPtr: // Meeting to AnyPtrs +const Type* TypeRawPtr::xmeet(const Type* t) const { + if (base() != RawPtr) { + typerr(t); + } + + switch (t->base()) { + case AnyPtr: break; - case RawPtr: { // might be top, bot, any/not or constant - enum PTR tptr = t->is_ptr()->ptr(); - enum PTR ptr = meet_ptr( tptr ); - if( ptr == Constant ) { // Cannot be equal constants, so... + case RawPtr: { + PTR tptr = t->is_ptr()->ptr(); + PTR ptr = meet_ptr(tptr); + if (ptr == Constant) { + // Same constant cases have been handled in Type::xmeet(const Type*, const Type*) if( tptr == Constant && _ptr != Constant) return t; if( _ptr == Constant && tptr != Constant) return this; ptr = NotNull; // Fall down in lattice @@ -3380,14 +3290,6 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const { return make( ptr ); } - case OopPtr: - case InstPtr: - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - return TypePtr::BOTTOM; // Oop meet raw is not well defined default: // All else is a mistake typerr(t); } @@ -3409,10 +3311,51 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const { return this; } -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeRawPtr::xdual() const { - return new TypeRawPtr(dual_ptr(), _bits, _reloc); +const Type* TypeRawPtr::xjoin(const Type* t) const { + if (base() != RawPtr) { + typerr(t); + } + + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + PTR ptr = join_ptr(tp->ptr()); + switch (tp->ptr()) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, Offset(tp->offset()), tp->speculative(), tp->inline_depth()); + case NotNull: + case BotPTR: + return this->ptr() == Constant ? this : make(ptr); + default: + typerr(t); + } + } + + case RawPtr: { + const TypeRawPtr* tp = t->is_rawptr(); + PTR ptr = join_ptr(tp->ptr()); + // this->ptr() can only be Constant, NotNull, BotPTR + if (ptr != Constant) { + // Neither is a constant + return make(ptr); + } + + // At least 1 is a constant + if (this->ptr() == Constant && tp->ptr() == Constant) { + assert(this->_bits != tp->_bits, "should have been handled in Type::xjoin"); + return TypePtr::make(AnyPtr, TopPTR, Offset(0)); + } else if (this->ptr() == Constant) { + return this; + } else { + assert(tp->ptr() == Constant, ""); + return tp; + } + } + + default: + typerr(t); + } } //------------------------------add_offset------------------------------------- @@ -3562,10 +3505,6 @@ uint TypeInterfaces::hash() const { return _hash; } -const Type* TypeInterfaces::xdual() const { - return this; -} - void TypeInterfaces::compute_hash() { uint hash = 0; for (int i = 0; i < _interfaces.length(); i++) { @@ -3721,12 +3660,6 @@ void TypeInterfaces::verify_is_loaded() const { } #endif -// Can't be implemented because there's no way to know if the type is above or below the center line. -const Type* TypeInterfaces::xmeet(const Type* t) const { - ShouldNotReachHere(); - return Type::xmeet(t); -} - bool TypeInterfaces::singleton(void) const { ShouldNotReachHere(); return Type::singleton(); @@ -3751,9 +3684,13 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter _is_ptr_to_strict_final_field(false), _instance_id(instance_id) { #ifdef ASSERT + assert((o != nullptr) == (ptr == TypePtr::Constant), "inconsistent constant status"); + assert(xk || o == nullptr, "constant must have an exact klass"); if (klass() != nullptr && klass()->is_loaded()) { interfaces->verify_is_loaded(); } + assert(instance_id != InstanceTop, "must not have top instance_id"); + assert(ptr != Constant || instance_id == InstanceBot, "a constant cannot have an instance_id"); #endif if (Compile::current()->eliminate_boxing() && (t == InstPtr) && (offset.get() > 0) && xk && (k != nullptr) && k->is_instance_klass()) { @@ -3886,41 +3823,11 @@ const TypeKlassPtr* TypeOopPtr::as_klass_type(bool try_for_exact) const { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeOopPtr::xmeet_helper(const Type *t) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Current "this->_base" is OopPtr - switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - - default: // All else is a mistake +const Type* TypeOopPtr::xmeet_helper(const Type *t) const { + if (base() != OopPtr) { typerr(t); - - case RawPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - return TypePtr::BOTTOM; // Oop meet raw is not well defined - + } + switch (t->base()) { // switch on original type case AnyPtr: { // Found an AnyPtr type vs self-OopPtr type const TypePtr *tp = t->is_ptr(); @@ -3954,19 +3861,56 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const { case InstPtr: // For these, flip the call around to cut down case AryPtr: - return t->xmeet(this); // Call in reverse direction + return t->is_oopptr()->xmeet_helper(this); // Call in reverse direction - } // End of switch - return this; // Return the double constant + default: + typerr(t); + } } +const Type* TypeOopPtr::xjoin_helper(const Type* t) const { + if (base() != OopPtr) { + typerr(t); + } + + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + Offset offset = join_offset(tp->offset()); + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + const TypePtr* speculative = xjoin_speculative(tp); + int depth = join_inline_depth(tp->inline_depth()); + + switch (other_ptr) { + case Null: + case TopPTR: + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); + case BotPTR: + case NotNull: { + int instance_id = join_instance_id(InstanceBot); + return make(ptr, offset, instance_id, speculative, depth); + } + default: + typerr(t); + } + } + + case OopPtr: { + const TypeOopPtr* tp = t->is_oopptr(); + int instance_id = join_instance_id(tp->instance_id()); + const TypePtr* speculative = xjoin_speculative(tp); + int depth = join_inline_depth(tp->inline_depth()); + return make(join_ptr(tp->ptr()), join_offset(tp->offset()), instance_id, speculative, depth); + } + + case InstPtr: + case AryPtr: + return t->is_oopptr()->xjoin_helper(this); -//------------------------------xdual------------------------------------------ -// Dual of a pure heap pointer. No relevant klass or oop information. -const Type *TypeOopPtr::xdual() const { - assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here"); - assert(const_oop() == nullptr, "no constants here"); - return new TypeOopPtr(_base, dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), Offset::bottom, dual_instance_id(), dual_speculative(), dual_inline_depth()); + default: + typerr(t); + } } //--------------------------make_from_klass_common----------------------------- @@ -4010,16 +3954,17 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ // Determine null-free/flat properties bool flat; bool not_flat; + bool null_free; bool not_null_free; bool atomic; if (xk) { flat = array_klass->is_flat_array_klass(); not_flat = !flat; - bool is_null_free = array_klass->is_elem_null_free(); - not_null_free = !is_null_free; + null_free = array_klass->is_elem_null_free(); + not_null_free = !null_free; atomic = array_klass->is_elem_atomic(); - if (is_null_free) { + if (null_free) { etype = etype->join_speculative(NOTNULL)->is_oopptr(); } } else { @@ -4031,12 +3976,13 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ flat = false; bool not_inline = !exact_etype->can_be_inline_type(); + null_free = false; not_null_free = not_inline; not_flat = !UseArrayFlattening || not_inline || (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->maybe_flat_in_array()); atomic = not_flat; } - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, flat, not_flat, not_null_free, atomic); + const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, flat, not_flat, null_free, not_null_free, atomic); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can // slam nullptrs down in the subarrays. @@ -4046,7 +3992,7 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ // Element is an typeArray const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type()); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, - /* stable= */ false, /* flat= */ false, /* not_flat= */ true, /* not_null_free= */ true, true); + /* stable= */ false, /* flat= */ false, /* not_flat= */ true, /*null_free=*/ false, /* not_null_free= */ true, true); // We used to pass NotNull in here, asserting that the array pointer // is not-null. That was not true in general. const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0)); @@ -4082,7 +4028,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const } bool is_atomic = o->as_array()->is_atomic(); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ is_flat, - /* not_flat= */ !is_flat, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic); + /* not_flat= */ !is_flat, /*null_free=*/ is_null_free, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can // slam nulls down in the subarrays. @@ -4095,7 +4041,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const // Element is an typeArray const Type* etype = (Type*)get_const_basic_type(klass->as_type_array_klass()->element_type()); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ false, - /* not_flat= */ true, /* not_null_free= */ true, true); + /* not_flat= */ true, /*null_free=*/ false, /* not_null_free= */ true, true); // We used to pass NotNull in here, asserting that the array pointer // is not-null. That was not true in general. if (make_constant) { @@ -4264,23 +4210,31 @@ int TypeOopPtr::meet_instance_id( int instance_id ) const { return _instance_id; } -//------------------------------dual_instance_id-------------------------------- -int TypeOopPtr::dual_instance_id( ) const { - if( _instance_id == InstanceTop ) return InstanceBot; // Map TOP into BOTTOM - if( _instance_id == InstanceBot ) return InstanceTop; // Map BOTTOM into TOP - return _instance_id; // Map everything else into self +int TypeOopPtr::join_instance_id(int uid) const { + if (_instance_id == InstanceBot) { + return uid; + } else if (uid == InstanceBot) { + return _instance_id; + } + if (_instance_id != uid) { + return InstanceTop; + } else { + return _instance_id; + } } - const TypeInterfaces* TypeOopPtr::meet_interfaces(const TypeOopPtr* other) const { - if (above_centerline(_ptr) && above_centerline(other->_ptr)) { - return _interfaces->union_with(other->_interfaces); - } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) { - return other->_interfaces; - } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) { - return _interfaces; + if (above_centerline(ptr()) || above_centerline(other->ptr())) { + typerr(other); + } + return interfaces()->intersection_with(other->interfaces()); +} + +const TypeInterfaces* TypeOopPtr::join_interfaces(const TypeOopPtr* other) const { + if (above_centerline(ptr()) || above_centerline(other->ptr())) { + typerr(other); } - return _interfaces->intersection_with(other->_interfaces); + return interfaces()->union_with(other->interfaces()); } /** @@ -4332,6 +4286,8 @@ TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, assert(k != nullptr && (k->is_loaded() || o == nullptr), "cannot have constants with non-loaded klass"); + assert(!xk || k->is_loaded(), "pointer to an oop of an exact type must be loaded"); + assert(!xk || interfaces->eq(k->as_instance_klass()), "inconsistency between k and interfaces"); }; //------------------------------make------------------------------------------- @@ -4432,114 +4388,24 @@ const TypeInstPtr* TypeInstPtr::cast_to_instance_id(int instance_id) const { return make(_ptr, klass(), _interfaces, _klass_is_exact, const_oop(), _offset, _flat_in_array, instance_id, _speculative, _inline_depth); } -//------------------------------xmeet_unloaded--------------------------------- -// Compute the MEET of two InstPtrs when at least one is unloaded. -// Assume classes are different since called after check for same name/class-loader -const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const { - Offset off = meet_offset(tinst->offset()); - PTR ptr = meet_ptr(tinst->ptr()); - int instance_id = meet_instance_id(tinst->instance_id()); - const TypePtr* speculative = xmeet_speculative(tinst); - int depth = meet_inline_depth(tinst->inline_depth()); - - const TypeInstPtr *loaded = is_loaded() ? this : tinst; - const TypeInstPtr *unloaded = is_loaded() ? tinst : this; - if( loaded->klass()->equals(ciEnv::current()->Object_klass()) ) { - // - // Meet unloaded class with java/lang/Object - // - // Meet - // | Unloaded Class - // Object | TOP | AnyNull | Constant | NotNull | BOTTOM | - // =================================================================== - // TOP | ..........................Unloaded......................| - // AnyNull | U-AN |................Unloaded......................| - // Constant | ... O-NN .................................. | O-BOT | - // NotNull | ... O-NN .................................. | O-BOT | - // BOTTOM | ........................Object-BOTTOM ..................| - // - assert(loaded->ptr() != TypePtr::Null, "insanity check"); - // - if (loaded->ptr() == TypePtr::TopPTR) { return unloaded->with_speculative(speculative); } - else if (loaded->ptr() == TypePtr::AnyNull) { - FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tinst->flat_in_array()); - return make(ptr, unloaded->klass(), interfaces, false, nullptr, off, flat_in_array, instance_id, - speculative, depth); - } - else if (loaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM->with_speculative(speculative); } - else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) { - if (unloaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM->with_speculative(speculative); } - else { return TypeInstPtr::NOTNULL->with_speculative(speculative); } - } - else if (unloaded->ptr() == TypePtr::TopPTR) { return unloaded->with_speculative(speculative); } - - return unloaded->cast_to_ptr_type(TypePtr::AnyNull)->is_instptr()->with_speculative(speculative); - } - - // Both are unloaded, not the same class, not Object - // Or meet unloaded with a different loaded class, not java/lang/Object - if (ptr != TypePtr::BotPTR) { - return TypeInstPtr::NOTNULL->with_speculative(speculative); - } - return TypeInstPtr::BOTTOM->with_speculative(speculative); -} - - //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeInstPtr::xmeet_helper(const Type *t) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? +const Type* TypeInstPtr::xmeet_helper(const Type* t) const { + if (base() != InstPtr) { + typerr(t); + } // Current "this->_base" is Pointer switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - default: // All else is a mistake typerr(t); - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case RawPtr: return TypePtr::BOTTOM; - - case AryPtr: { // All arrays inherit from Object class - // Call in reverse direction to avoid duplication - return t->is_aryptr()->xmeet_helper(this); - } - case OopPtr: { // Meeting to OopPtrs // Found a OopPtr type vs self-InstPtr type const TypeOopPtr *tp = t->is_oopptr(); Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { - case TopPTR: - case AnyNull: { - int instance_id = meet_instance_id(InstanceTop); - const TypePtr* speculative = xmeet_speculative(tp); - int depth = meet_inline_depth(tp->inline_depth()); - return make(ptr, klass(), _interfaces, klass_is_exact(), - (ptr == Constant ? const_oop() : nullptr), offset, flat_in_array(), instance_id, speculative, depth); - } case NotNull: case BotPTR: { int instance_id = meet_instance_id(tp->instance_id()); @@ -4575,230 +4441,47 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { } } - /* - A-top } - / | \ } Tops - B-top A-any C-top } - | / | \ | } Any-nulls - B-any | C-any } - | | | - B-con A-con C-con } constants; not comparable across classes - | | | - B-not | C-not } - | \ | / | } not-nulls - B-bot A-not C-bot } - \ | / } Bottoms - A-bot } - */ - - case InstPtr: { // Meeting 2 Oops? - // Found an InstPtr sub-type vs self-InstPtr type - const TypeInstPtr *tinst = t->is_instptr(); - Offset off = meet_offset(tinst->offset()); - PTR ptr = meet_ptr(tinst->ptr()); - int instance_id = meet_instance_id(tinst->instance_id()); - const TypePtr* speculative = xmeet_speculative(tinst); - int depth = meet_inline_depth(tinst->inline_depth()); - const TypeInterfaces* interfaces = meet_interfaces(tinst); - - ciKlass* tinst_klass = tinst->klass(); - ciKlass* this_klass = klass(); - - ciKlass* res_klass = nullptr; - bool res_xk = false; - const Type* res; - MeetResult kind = meet_instptr(ptr, interfaces, this, tinst, res_klass, res_xk); - - if (kind == UNLOADED) { - // One of these classes has not been loaded - const TypeInstPtr* unloaded_meet = xmeet_unloaded(tinst, interfaces); -#ifndef PRODUCT - if (PrintOpto && Verbose) { - tty->print("meet of unloaded classes resulted in: "); - unloaded_meet->dump(); - tty->cr(); - tty->print(" this == "); - dump(); - tty->cr(); - tty->print(" tinst == "); - tinst->dump(); - tty->cr(); - } -#endif - res = unloaded_meet; - } else { - FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tinst->flat_in_array()); - if (kind == NOT_SUBTYPE && instance_id > 0) { - instance_id = InstanceBot; - } else if (kind == LCA) { - instance_id = InstanceBot; - } - ciObject* o = nullptr; // Assume not constant when done - ciObject* this_oop = const_oop(); - ciObject* tinst_oop = tinst->const_oop(); - if (ptr == Constant) { - if (this_oop != nullptr && tinst_oop != nullptr && - this_oop->equals(tinst_oop)) - o = this_oop; - else if (above_centerline(_ptr)) { - assert(!tinst_klass->is_interface(), ""); - o = tinst_oop; - } else if (above_centerline(tinst->_ptr)) { - assert(!this_klass->is_interface(), ""); - o = this_oop; - } else - ptr = NotNull; - } - res = make(ptr, res_klass, interfaces, res_xk, o, off, flat_in_array, instance_id, speculative, depth); - } - - return res; - - } // End of case InstPtr - + case InstPtr: + case AryPtr: + return TypeJavaPtrMeetHelper::javaptr_type_xmeet(this, t->is_oopptr()); } // End of switch - return this; // Return the double constant } -template TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type, const T* other_type, - ciKlass*& res_klass, bool& res_xk) { - ciKlass* this_klass = this_type->klass(); - ciKlass* other_klass = other_type->klass(); - - bool this_xk = this_type->klass_is_exact(); - bool other_xk = other_type->klass_is_exact(); - PTR this_ptr = this_type->ptr(); - PTR other_ptr = other_type->ptr(); - const TypeInterfaces* this_interfaces = this_type->interfaces(); - const TypeInterfaces* other_interfaces = other_type->interfaces(); - // Check for easy case; klasses are equal (and perhaps not loaded!) - // If we have constants, then we created oops so classes are loaded - // and we can handle the constants further down. This case handles - // both-not-loaded or both-loaded classes - if (ptr != Constant && this_klass->equals(other_klass) && this_xk == other_xk) { - res_klass = this_klass; - res_xk = this_xk; - return QUICK; - } - - // Classes require inspection in the Java klass hierarchy. Must be loaded. - if (!other_klass->is_loaded() || !this_klass->is_loaded()) { - return UNLOADED; - } - - // !!! Here's how the symmetry requirement breaks down into invariants: - // If we split one up & one down AND they subtype, take the down man. - // If we split one up & one down AND they do NOT subtype, "fall hard". - // If both are up and they subtype, take the subtype class. - // If both are up and they do NOT subtype, "fall hard". - // If both are down and they subtype, take the supertype class. - // If both are down and they do NOT subtype, "fall hard". - // Constants treated as down. - - // Now, reorder the above list; observe that both-down+subtype is also - // "fall hard"; "fall hard" becomes the default case: - // If we split one up & one down AND they subtype, take the down man. - // If both are up and they subtype, take the subtype class. - - // If both are down and they subtype, "fall hard". - // If both are down and they do NOT subtype, "fall hard". - // If both are up and they do NOT subtype, "fall hard". - // If we split one up & one down AND they do NOT subtype, "fall hard". - - // If a proper subtype is exact, and we return it, we return it exactly. - // If a proper supertype is exact, there can be no subtyping relationship! - // If both types are equal to the subtype, exactness is and-ed below the - // centerline and or-ed above it. (N.B. Constants are always exact.) - - const T* subtype = nullptr; - bool subtype_exact = false; - if (this_type->is_same_java_type_as(other_type)) { - // Same klass - subtype = this_type; - subtype_exact = below_centerline(ptr) ? (this_xk && other_xk) : (this_xk || other_xk); - } else if (!other_xk && this_type->is_meet_subtype_of(other_type)) { - subtype = this_type; // Pick subtyping class - subtype_exact = this_xk; - } else if (!this_xk && other_type->is_meet_subtype_of(this_type)) { - subtype = other_type; // Pick subtyping class - subtype_exact = other_xk; - } - - if (subtype != nullptr) { - if (above_centerline(ptr)) { - // Both types are empty. - this_type = other_type = subtype; - this_xk = other_xk = subtype_exact; - } else if (above_centerline(this_ptr) && !above_centerline(other_ptr)) { - // this_type is empty while other_type is not. Take other_type. - this_type = other_type; - this_xk = other_xk; - } else if (above_centerline(other_ptr) && !above_centerline(this_ptr)) { - // other_type is empty while this_type is not. Take this_type. - other_type = this_type; // this is down; keep down man - } else { - // this_type and other_type are both non-empty. - this_xk = subtype_exact; // either they are equal, or we'll do an LCA - } - } - - // Check for classes now being equal - if (this_type->is_same_java_type_as(other_type)) { - // If the klasses are equal, the constants may still differ. Fall to - // NotNull if they do (neither constant is null; that is a special case - // handled elsewhere). - res_klass = this_type->klass(); - res_xk = this_xk; - return SUBTYPE; - } // Else classes are not equal - - // Since klasses are different, we require a LCA in the Java - // class hierarchy - which means we have to fall to at least NotNull. - if (ptr == TopPTR || ptr == AnyNull || ptr == Constant) { - ptr = NotNull; +const Type* TypeInstPtr::xjoin_helper(const Type* t) const { + if (base() != InstPtr) { + typerr(t); } - interfaces = this_interfaces->intersection_with(other_interfaces); - - // Now we find the LCA of Java classes - ciKlass* k = this_klass->least_common_ancestor(other_klass); - - res_klass = k; - res_xk = false; - return LCA; -} + switch (t->base()) { + case AnyPtr: + case OopPtr: { + const TypePtr* tp = t->is_ptr(); + Offset offset = join_offset(tp->offset()); + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + const TypePtr* speculative = xjoin_speculative(tp); + int depth = join_inline_depth(tp->inline_depth()); + + switch (other_ptr) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); + case NotNull: + case BotPTR: { + int instance_id = join_instance_id(InstanceBot); + return make(ptr, klass(), interfaces(), klass_is_exact(), const_oop(), offset, flat_in_array(), instance_id, speculative, depth); + } + default: + typerr(t); + } + } -// Top-Flat Flat Not-Flat Maybe-Flat -// ------------------------------------------------------------- -// Top-Flat Top-Flat Flat Not-Flat Maybe-Flat -// Flat Flat Flat Maybe-Flat Maybe-Flat -// Not-Flat Not-Flat Maybe-Flat Not-Flat Maybe-Flat -// Maybe-Flat Maybe-Flat Maybe-Flat Maybe-Flat Maybe-flat -TypePtr::FlatInArray TypePtr::meet_flat_in_array(const FlatInArray left, const FlatInArray right) { - if (left == TopFlat) { - return right; - } - if (right == TopFlat) { - return left; - } - if (left == MaybeFlat || right == MaybeFlat) { - return MaybeFlat; - } + case InstPtr: + case AryPtr: + return TypeJavaPtrJoinHelper::javaptr_type_xjoin(this, t->is_oopptr()); - switch (left) { - case Flat: - if (right == Flat) { - return Flat; - } - return MaybeFlat; - case NotFlat: - if (right == NotFlat) { - return NotFlat; - } - return MaybeFlat; default: - ShouldNotReachHere(); - return Uninitialized; + typerr(t); } } @@ -4812,15 +4495,6 @@ ciType* TypeInstPtr::java_mirror_type() const { return const_oop()->as_instance()->java_mirror_type(); } - -//------------------------------xdual------------------------------------------ -// Dual: do NOT dual on klasses. This means I do NOT understand the Java -// inheritance mechanism. -const Type* TypeInstPtr::xdual() const { - return new TypeInstPtr(dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), - dual_flat_in_array(), dual_instance_id(), dual_speculative(), dual_inline_depth()); -} - //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypeInstPtr::eq( const Type *t ) const { @@ -4955,67 +4629,6 @@ const TypeKlassPtr* TypeInstPtr::as_klass_type(bool try_for_exact) const { return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), _interfaces, Offset(0), flat_in_array); } -template bool TypePtr::is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk) { - static_assert(std::is_base_of::value, ""); - - if (!this_one->is_instance_type(other)) { - return false; - } - - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty()) { - return true; - } - - return this_one->klass()->is_subtype_of(other->klass()) && - (!this_xk || this_one->_interfaces->contains(other->_interfaces)); -} - - -bool TypeInstPtr::is_meet_subtype_of_helper(const TypeOopPtr *other, bool this_xk, bool other_xk) const { - return TypePtr::is_meet_subtype_of_helper_for_instance(this, other, this_xk, other_xk); -} - -template bool TypePtr::is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk) { - static_assert(std::is_base_of::value, ""); - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty()) { - return true; - } - - if (this_one->is_instance_type(other)) { - return other->klass() == ciEnv::current()->Object_klass() && this_one->_interfaces->contains(other->_interfaces); - } - - int dummy; - bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM); - if (this_top_or_bottom) { - return false; - } - - const T1* other_ary = this_one->is_array_type(other); - const TypePtr* other_elem = other_ary->elem()->make_ptr(); - const TypePtr* this_elem = this_one->elem()->make_ptr(); - if (other_elem != nullptr && this_elem != nullptr) { - return this_one->is_reference_type(this_elem)->is_meet_subtype_of_helper(this_one->is_reference_type(other_elem), this_xk, other_xk); - } - if (other_elem == nullptr && this_elem == nullptr) { - return this_one->klass()->is_subtype_of(other->klass()); - } - - return false; -} - -bool TypeAryPtr::is_meet_subtype_of_helper(const TypeOopPtr *other, bool this_xk, bool other_xk) const { - return TypePtr::is_meet_subtype_of_helper_for_array(this, other, this_xk, other_xk); -} - -bool TypeInstKlassPtr::is_meet_subtype_of_helper(const TypeKlassPtr *other, bool this_xk, bool other_xk) const { - return TypePtr::is_meet_subtype_of_helper_for_instance(this, other, this_xk, other_xk); -} - -bool TypeAryKlassPtr::is_meet_subtype_of_helper(const TypeKlassPtr *other, bool this_xk, bool other_xk) const { - return TypePtr::is_meet_subtype_of_helper_for_array(this, other, this_xk, other_xk); -} - //============================================================================= // Convenience common pre-built types. const TypeAryPtr* TypeAryPtr::BOTTOM; @@ -5136,7 +4749,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const { assert(new_size != nullptr, ""); new_size = narrow_size_type(new_size); if (new_size == size()) return this; - const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable(), is_flat(), is_not_flat(), is_null_free(), is_not_null_free(), is_atomic()); return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } @@ -5145,7 +4758,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_flat(bool flat) const { return this; } assert(!flat || !is_not_flat(), "inconsistency"); - const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), flat, is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), flat, is_not_flat(), is_null_free(), is_not_null_free(), is_atomic()); const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); if (res->speculative() == res->remove_speculative()) { return res->remove_speculative(); @@ -5159,7 +4772,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_not_flat(bool not_flat) const { return this; } assert(!not_flat || !is_flat(), "inconsistency"); - const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), not_flat, is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), not_flat, is_null_free(), is_not_null_free(), is_atomic()); const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); // We keep the speculative part if it contains information about flat-/nullability. // Make sure it's removed if it's not better than the non-speculative type anymore. @@ -5182,7 +4795,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_null_free(bool null_free) const { new_elem = new_elem->meet_speculative(TypePtr::NULL_PTR); } new_elem = elem->isa_narrowoop() ? new_elem->make_narrowoop() : new_elem; - const TypeAry* new_ary = TypeAry::make(new_elem, size(), is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(new_elem, size(), is_stable(), is_flat(), is_not_flat(), null_free, is_not_null_free(), is_atomic()); const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); if (res->speculative() == res->remove_speculative()) { return res->remove_speculative(); @@ -5198,7 +4811,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_not_null_free(bool not_null_free) const { return this; } assert(!not_null_free || !is_null_free(), "inconsistency"); - const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), is_not_flat(), not_null_free, is_atomic()); + const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), is_not_flat(), is_null_free(), not_null_free, is_atomic()); const TypePtr* new_spec = _speculative; if (new_spec != nullptr) { // Could be 'null free' from profiling, which would contradict the cast. @@ -5263,7 +4876,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1); } - const TypeAry* new_ary = TypeAry::make(elem, size(), stable, is_flat(), is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(elem, size(), stable, is_flat(), is_not_flat(), is_null_free(), is_not_null_free(), is_atomic()); return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } @@ -5285,7 +4898,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_autobox_cache() const { if (etype == nullptr) return this; // The pointers in the autobox arrays are always non-null. etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr(); - const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable(), is_flat(), is_not_flat(), is_null_free(), is_not_null_free(), is_atomic()); return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, /*is_autobox_cache=*/true); } @@ -5318,31 +4931,13 @@ bool TypeAryPtr::maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this } //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypeAryPtr::xmeet_helper(const Type *t) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? +const Type* TypeAryPtr::xmeet_helper(const Type* t) const { + if (base() != AryPtr) { + typerr(t); + } + // Current "this->_base" is Pointer switch (t->base()) { // switch on original type - - // Mixing ints & oops happens when javac reuses local variables - case Int: - case Long: - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - default: // All else is a mistake typerr(t); @@ -5354,12 +4949,6 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int depth = meet_inline_depth(tp->inline_depth()); const TypePtr* speculative = xmeet_speculative(tp); switch (tp->ptr()) { - case TopPTR: - case AnyNull: { - int instance_id = meet_instance_id(InstanceTop); - return make(ptr, (ptr == Constant ? const_oop() : nullptr), - _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); - } case BotPTR: case NotNull: { int instance_id = meet_instance_id(tp->instance_id()); @@ -5394,293 +4983,48 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { } } - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case RawPtr: return TypePtr::BOTTOM; - - case AryPtr: { // Meeting 2 references? - const TypeAryPtr *tap = t->is_aryptr(); - Offset off = meet_offset(tap->offset()); - Offset field_off = meet_field_offset(tap->field_offset()); - const Type* tm = _ary->meet_speculative(tap->_ary); - const TypeAry* tary = tm->isa_ary(); - if (tary == nullptr) { - assert(tm == Type::TOP || tm == Type::BOTTOM, ""); - return tm; - } - PTR ptr = meet_ptr(tap->ptr()); - int instance_id = meet_instance_id(tap->instance_id()); - const TypePtr* speculative = xmeet_speculative(tap); - int depth = meet_inline_depth(tap->inline_depth()); - - ciKlass* res_klass = nullptr; - bool res_xk = false; - bool res_flat = false; - bool res_not_flat = false; - bool res_not_null_free = false; - bool res_atomic = false; - const Type* elem = tary->_elem; - if (meet_aryptr(ptr, elem, this, tap, res_klass, res_xk, res_flat, res_not_flat, res_not_null_free, res_atomic) == NOT_SUBTYPE) { - instance_id = InstanceBot; - } else if (this->is_flat() != tap->is_flat()) { - // Meeting flat inline type array with non-flat array. Adjust (field) offset accordingly. - if (tary->_flat) { - // Result is in a flat representation - off = Offset(is_flat() ? offset() : tap->offset()); - field_off = is_flat() ? field_offset() : tap->field_offset(); - } else if (below_centerline(ptr)) { - // Result is in a non-flat representation - off = Offset(flat_offset()).meet(Offset(tap->flat_offset())); - field_off = (field_off == Offset::top) ? Offset::top : Offset::bottom; - } else if (flat_offset() == tap->flat_offset()) { - off = Offset(!is_flat() ? offset() : tap->offset()); - field_off = !is_flat() ? field_offset() : tap->field_offset(); - } - } - - ciObject* o = nullptr; // Assume not constant when done - ciObject* this_oop = const_oop(); - ciObject* tap_oop = tap->const_oop(); - if (ptr == Constant) { - if (this_oop != nullptr && tap_oop != nullptr && - this_oop->equals(tap_oop)) { - o = tap_oop; - } else if (above_centerline(_ptr)) { - o = tap_oop; - } else if (above_centerline(tap->_ptr)) { - o = this_oop; - } else { - ptr = NotNull; - } - } - return make(ptr, o, TypeAry::make(elem, tary->_size, tary->_stable, res_flat, res_not_flat, res_not_null_free, res_atomic), res_klass, res_xk, off, field_off, instance_id, speculative, depth); - } - - // All arrays inherit from Object class - case InstPtr: { - const TypeInstPtr *tp = t->is_instptr(); - Offset offset = meet_offset(tp->offset()); - PTR ptr = meet_ptr(tp->ptr()); - int instance_id = meet_instance_id(tp->instance_id()); - const TypePtr* speculative = xmeet_speculative(tp); - int depth = meet_inline_depth(tp->inline_depth()); - const TypeInterfaces* interfaces = meet_interfaces(tp); - const TypeInterfaces* tp_interfaces = tp->_interfaces; - const TypeInterfaces* this_interfaces = _interfaces; - - switch (ptr) { - case TopPTR: - case AnyNull: // Fall 'down' to dual of object klass - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need to - // do the same here. - // - // Flat in array: - // We do - // dual(TypeAryPtr) MEET dual(TypeInstPtr) - // If TypeInstPtr is anything else than Object, then the result of the meet is bottom Object (i.e. we could have - // instances or arrays). - // If TypeInstPtr is an Object and either - // - exact - // - inexact AND flat in array == dual(not flat in array) (i.e. not an array type) - // then the result of the meet is bottom Object (i.e. we could have instances or arrays). - // Otherwise, we meet two array pointers and create a new TypeAryPtr. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && - !tp->klass_is_exact() && !tp->is_not_flat_in_array()) { - return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); - } else { - // cannot subclass, so the meet has to fall badly below the centerline - ptr = NotNull; - instance_id = InstanceBot; - interfaces = this_interfaces->intersection_with(tp_interfaces); - FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array()); - return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, depth); - } - case Constant: - case NotNull: - case BotPTR: { // Fall down to object klass - // LCA is object_klass, but if we subclass from the top we can do better - if (above_centerline(tp->ptr())) { - // If 'tp' is above the centerline and it is Object class - // then we can subclass in the Java class hierarchy. - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need - // to do the same here. - - // Flat in array: We do TypeAryPtr MEET dual(TypeInstPtr), same applies as above in TopPTR/AnyNull case. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && - !tp->klass_is_exact() && !tp->is_not_flat_in_array()) { - // that is, my array type is a subtype of 'tp' klass - return make(ptr, (ptr == Constant ? const_oop() : nullptr), - _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); - } - } - // The other case cannot happen, since t cannot be a subtype of an array. - // The meet falls down to Object class below centerline. - if (ptr == Constant) { - ptr = NotNull; - } - if (instance_id > 0) { - instance_id = InstanceBot; - } - - FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array()); - interfaces = this_interfaces->intersection_with(tp_interfaces); - return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, - flat_in_array, instance_id, speculative, depth); - } - default: typerr(t); - } - } + case AryPtr: + case InstPtr: + return TypeJavaPtrMeetHelper::javaptr_type_xmeet(this, t->is_oopptr()); } - return this; // Lint noise } - -template TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary, - ciKlass*& res_klass, bool& res_xk, bool &res_flat, bool& res_not_flat, bool& res_not_null_free, bool &res_atomic) { - int dummy; - bool this_top_or_bottom = (this_ary->base_element_type(dummy) == Type::TOP || this_ary->base_element_type(dummy) == Type::BOTTOM); - bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM); - ciKlass* this_klass = this_ary->klass(); - ciKlass* other_klass = other_ary->klass(); - bool this_xk = this_ary->klass_is_exact(); - bool other_xk = other_ary->klass_is_exact(); - PTR this_ptr = this_ary->ptr(); - PTR other_ptr = other_ary->ptr(); - bool this_flat = this_ary->is_flat(); - bool this_not_flat = this_ary->is_not_flat(); - bool other_flat = other_ary->is_flat(); - bool other_not_flat = other_ary->is_not_flat(); - bool this_not_null_free = this_ary->is_not_null_free(); - bool other_not_null_free = other_ary->is_not_null_free(); - bool this_atomic = this_ary->is_atomic(); - bool other_atomic = other_ary->is_atomic(); - const bool same_nullness = this_ary->is_null_free() == other_ary->is_null_free(); - res_klass = nullptr; - MeetResult result = SUBTYPE; - res_flat = this_flat && other_flat; - bool res_null_free = this_ary->is_null_free() && other_ary->is_null_free(); - res_not_flat = this_not_flat && other_not_flat; - res_not_null_free = this_not_null_free && other_not_null_free; - res_atomic = this_atomic && other_atomic; - - if (elem->isa_int()) { - // Integral array element types have irrelevant lattice relations. - // It is the klass that determines array layout, not the element type. - if (this_top_or_bottom) { - res_klass = other_klass; - } else if (other_top_or_bottom || other_klass == this_klass) { - res_klass = this_klass; - } else { - // Something like byte[int+] meets char[int+]. - // This must fall to bottom, not (int[-128..65535])[int+]. - // instance_id = InstanceBot; - elem = Type::BOTTOM; - result = NOT_SUBTYPE; - if (above_centerline(ptr) || ptr == Constant) { - ptr = NotNull; - res_xk = false; - return NOT_SUBTYPE; - } - } - } else {// Non integral arrays. - // Must fall to bottom if exact klasses in upper lattice - // are not equal or super klass is exact. - if ((above_centerline(ptr) || ptr == Constant) && !this_ary->is_same_java_type_as(other_ary) && - // meet with top[] and bottom[] are processed further down: - !this_top_or_bottom && !other_top_or_bottom && - // both are exact and not equal: - ((other_xk && this_xk) || - // 'tap' is exact and super or unrelated: - (other_xk && !other_ary->is_meet_subtype_of(this_ary)) || - // 'this' is exact and super or unrelated: - (this_xk && !this_ary->is_meet_subtype_of(other_ary)))) { - if (above_centerline(ptr) || (elem->make_ptr() && above_centerline(elem->make_ptr()->_ptr))) { - elem = Type::BOTTOM; - } - ptr = NotNull; - res_xk = false; - return NOT_SUBTYPE; - } +const Type* TypeAryPtr::xjoin_helper(const Type* t) const { + if (base() != AryPtr) { + typerr(t); } - res_xk = false; - switch (other_ptr) { - case AnyNull: - case TopPTR: - // Compute new klass on demand, do not use tap->_klass - if (below_centerline(this_ptr)) { - res_xk = this_xk; - if (this_ary->is_flat()) { - elem = this_ary->elem(); + switch (t->base()) { + case AnyPtr: + case OopPtr: { + const TypePtr* tp = t->is_ptr(); + Offset offset = join_offset(tp->offset()); + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + const TypePtr* speculative = xjoin_speculative(tp); + int depth = join_inline_depth(tp->inline_depth()); + + switch (other_ptr) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); + case NotNull: + case BotPTR: { + int instance_id = join_instance_id(InstanceBot); + return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), offset, field_offset(), instance_id, speculative, depth, is_autobox_cache()); } - } else { - res_xk = (other_xk || this_xk); + default: + typerr(t); } - break; - case Constant: { - if (this_ptr == Constant && same_nullness) { - // Only exact if same nullness since: - // null-free [LMyValue <: nullable [LMyValue. - res_xk = true; - } else if (above_centerline(this_ptr)) { - res_xk = true; - } else { - // Only precise for identical arrays - res_xk = this_xk && (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom)); - // Even though MyValue is final, [LMyValue is only exact if the array - // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue. - if (res_xk && !res_null_free && !res_not_null_free) { - ptr = NotNull; - res_xk = false; - } - } - break; - } - case NotNull: - case BotPTR: - // Compute new klass on demand, do not use tap->_klass - if (above_centerline(this_ptr)) { - res_xk = other_xk; - if (other_ary->is_flat()) { - elem = other_ary->elem(); - } - } else { - res_xk = (other_xk && this_xk) && - (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom)); // Only precise for identical arrays - // Even though MyValue is final, [LMyValue is only exact if the array - // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue. - if (res_xk && !res_null_free && !res_not_null_free) { - res_xk = false; - } - } - break; - default: { - ShouldNotReachHere(); - return result; } - } - return result; -} + case InstPtr: + case AryPtr: + return TypeJavaPtrJoinHelper::javaptr_type_xjoin(this, t->is_oopptr()); -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeAryPtr::xdual() const { - bool xk = _klass_is_exact; - return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(), _klass, xk, dual_offset(), dual_field_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth()); -} - -Type::Offset TypeAryPtr::meet_field_offset(const Type::Offset offset) const { - return _field_offset.meet(offset); -} - -//------------------------------dual_offset------------------------------------ -Type::Offset TypeAryPtr::dual_field_offset() const { - return _field_offset.dual(); + default: + typerr(t); + } } //------------------------------dump2------------------------------------------ @@ -5918,12 +5262,6 @@ bool TypeNarrowPtr::eq( const Type *t ) const { return false; } -const Type *TypeNarrowPtr::xdual() const { // Compute dual right now. - const TypePtr* odual = _ptrtype->dual()->is_ptr(); - return make_same_narrowptr(odual); -} - - const Type *TypeNarrowPtr::filter_helper(const Type *kills, bool include_speculative) const { if (isa_same_narrowptr(kills)) { const Type* ft =_ptrtype->filter_helper(is_same_narrowptr(kills)->_ptrtype, include_speculative); @@ -5943,58 +5281,6 @@ const Type *TypeNarrowPtr::filter_helper(const Type *kills, bool include_specula } } -//------------------------------xmeet------------------------------------------ -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeNarrowPtr::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - if (t->base() == base()) { - const Type* result = _ptrtype->xmeet(t->make_ptr()); - if (result->isa_ptr()) { - return make_hash_same_narrowptr(result->is_ptr()); - } - return result; - } - - // Current "this->_base" is NarrowKlass or NarrowOop - switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case AnyPtr: - case RawPtr: - case OopPtr: - case InstPtr: - case AryPtr: - case MetadataPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - - default: // All else is a mistake - typerr(t); - - } // End of switch - - return this; -} - #ifndef PRODUCT void TypeNarrowPtr::dump2( Dict & d, uint depth, outputStream *st ) const { _ptrtype->dump2(d, depth, st); @@ -6111,30 +5397,11 @@ const TypeMetadataPtr* TypeMetadataPtr::cast_to_ptr_type(PTR ptr) const { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. const Type *TypeMetadataPtr::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? + if (base() != MetadataPtr) { + typerr(t); + } - // Current "this->_base" is OopPtr switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - default: // All else is a mistake typerr(t); @@ -6158,15 +5425,6 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { } } - case RawPtr: - case KlassPtr: - case InstKlassPtr: - case AryKlassPtr: - case OopPtr: - case InstPtr: - case AryPtr: - return TypePtr::BOTTOM; // Oop meet raw is not well defined - case MetadataPtr: { const TypeMetadataPtr *tp = t->is_metadataptr(); Offset offset = meet_offset(tp->offset()); @@ -6187,14 +5445,53 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { break; } } // End of switch - return this; // Return the double constant } +const Type* TypeMetadataPtr::xjoin(const Type* t) const { + if (base() != MetadataPtr) { + typerr(t); + } -//------------------------------xdual------------------------------------------ -// Dual of a pure metadata pointer. -const Type *TypeMetadataPtr::xdual() const { - return new TypeMetadataPtr(dual_ptr(), metadata(), dual_offset()); + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + PTR ptr = join_ptr(tp->ptr()); + Offset offset = join_offset(tp->offset()); + switch (tp->ptr()) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); + case NotNull: + case BotPTR: + return make(ptr, _metadata, offset); + default: + typerr(t); + } + } + + case MetadataPtr: { + const TypeMetadataPtr* tp = t->is_metadataptr(); + PTR ptr = join_ptr(tp->ptr()); + Offset offset = join_offset(tp->offset()); + if (offset == Offset::top) { + return TypePtr::make(AnyPtr, TopPTR, offset); + } + + ciMetadata* metadata = this->metadata(); + if (ciMetadata* meta2 = tp->metadata(); meta2 != nullptr) { + if (metadata == nullptr) { + metadata = meta2; + } else if (!metadata->equals(meta2)) { + return TypePtr::make(AnyPtr, ptr == TypePtr::BotPTR ? Null : TopPTR, offset); + } + } + + return make(ptr, metadata, offset); + } + + default: + typerr(t); + } } //------------------------------dump2------------------------------------------ @@ -6321,14 +5618,17 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat } const TypeInterfaces* TypeKlassPtr::meet_interfaces(const TypeKlassPtr* other) const { - if (above_centerline(_ptr) && above_centerline(other->_ptr)) { - return _interfaces->union_with(other->_interfaces); - } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) { - return other->_interfaces; - } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) { - return _interfaces; + if (above_centerline(ptr()) || above_centerline(other->ptr())) { + typerr(other); + } + return interfaces()->intersection_with(other->interfaces()); +} + +const TypeInterfaces* TypeKlassPtr::join_interfaces(const TypeKlassPtr* other) const { + if (above_centerline(ptr()) || above_centerline(other->ptr())) { + typerr(other); } - return _interfaces->intersection_with(other->_interfaces); + return interfaces()->union_with(other->interfaces()); } //------------------------------get_con---------------------------------------- @@ -6463,31 +5763,13 @@ const TypeInstPtr* TypeInstKlassPtr::as_subtype_instance_type(bool klass_change) //------------------------------xmeet------------------------------------------ // Compute the MEET of two types, return a new Type object. -const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? +const Type* TypeInstKlassPtr::xmeet(const Type* t) const { + if (base() != InstKlassPtr) { + typerr(t); + } // Current "this->_base" is Pointer switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - default: // All else is a mistake typerr(t); @@ -6510,117 +5792,43 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { } } - case RawPtr: - case MetadataPtr: - case OopPtr: - case AryPtr: // Meet with AryPtr - case InstPtr: // Meet with InstPtr - return TypePtr::BOTTOM; + case InstKlassPtr: + case AryKlassPtr: + return TypeJavaPtrMeetHelper::javaptr_type_xmeet(this, t->is_klassptr()); - // - // A-top } - // / | \ } Tops - // B-top A-any C-top } - // | / | \ | } Any-nulls - // B-any | C-any } - // | | | - // B-con A-con C-con } constants; not comparable across classes - // | | | - // B-not | C-not } - // | \ | / | } not-nulls - // B-bot A-not C-bot } - // \ | / } Bottoms - // A-bot } - // + } // End of switch + return this; // Return the double constant +} - case InstKlassPtr: { // Meet two KlassPtr types - const TypeInstKlassPtr *tkls = t->is_instklassptr(); - Offset off = meet_offset(tkls->offset()); - PTR ptr = meet_ptr(tkls->ptr()); - const TypeInterfaces* interfaces = meet_interfaces(tkls); - - ciKlass* res_klass = nullptr; - bool res_xk = false; - const FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tkls->flat_in_array()); - switch (meet_instptr(ptr, interfaces, this, tkls, res_klass, res_xk)) { - case UNLOADED: - ShouldNotReachHere(); - case SUBTYPE: - case NOT_SUBTYPE: - case LCA: - case QUICK: { - assert(res_xk == (ptr == Constant), ""); - const Type* res = make(ptr, res_klass, interfaces, off, flat_in_array); - return res; - } - default: - ShouldNotReachHere(); - } - } // End of case KlassPtr - case AryKlassPtr: { // All arrays inherit from Object class - const TypeAryKlassPtr *tp = t->is_aryklassptr(); - Offset offset = meet_offset(tp->offset()); - PTR ptr = meet_ptr(tp->ptr()); - const TypeInterfaces* interfaces = meet_interfaces(tp); - const TypeInterfaces* tp_interfaces = tp->_interfaces; - const TypeInterfaces* this_interfaces = _interfaces; +const Type* TypeInstKlassPtr::xjoin(const Type* t) const { + if (base() != InstKlassPtr) { + typerr(t); + } - switch (ptr) { - case TopPTR: - case AnyNull: // Fall 'down' to dual of object klass - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need to - // do the same here. - // - // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper(). - if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && - !klass_is_exact() && !is_not_flat_in_array()) { - return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset, tp->is_not_flat(), tp->is_not_null_free(), tp->is_flat(), tp->is_null_free(), tp->is_atomic(), tp->is_refined_type()); - } else { - // cannot subclass, so the meet has to fall badly below the centerline - ptr = NotNull; - interfaces = _interfaces->intersection_with(tp->_interfaces); - FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, NotFlat); - return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array); + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + PTR ptr = join_ptr(tp->ptr()); + Offset offset = join_offset(tp->offset()); + switch (tp->ptr()) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); + case NotNull: + case BotPTR: + return make(ptr, klass(), interfaces(), offset); + default: + typerr(t); } - case Constant: - case NotNull: - case BotPTR: { // Fall down to object klass - // LCA is object_klass, but if we subclass from the top we can do better - if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull ) - // If 'this' (InstPtr) is above the centerline and it is Object class - // then we can subclass in the Java class hierarchy. - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need - // to do the same here. - // - // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper(). - if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && - !klass_is_exact() && !is_not_flat_in_array()) { - // that is, tp's array type is a subtype of my klass - return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset, tp->is_not_flat(), tp->is_not_null_free(), tp->is_flat(), tp->is_null_free(), tp->is_atomic(), tp->is_refined_type()); - } - } - // The other case cannot happen, since I cannot be a subtype of an array. - // The meet falls down to Object class below centerline. - if( ptr == Constant ) - ptr = NotNull; - interfaces = this_interfaces->intersection_with(tp_interfaces); - FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, NotFlat); - return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array); - } - default: typerr(t); } - } - } // End of switch - return this; // Return the double constant -} + case InstKlassPtr: + case AryKlassPtr: + return TypeJavaPtrJoinHelper::javaptr_type_xjoin(this, t->is_klassptr()); -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type* TypeInstKlassPtr::xdual() const { - return new TypeInstKlassPtr(dual_ptr(), klass(), _interfaces, dual_offset(), dual_flat_in_array()); + default: + typerr(t); + } } template bool TypePtr::is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact) { @@ -6765,6 +5973,10 @@ bool TypeAryPtr::can_be_inline_array() const { } const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* k, Offset offset, bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined_type) { + if (ptr == TypePtr::Constant && elem->isa_klassptr() != nullptr) { + // If an array klass ptr is a constant, its element is also a constant + elem = elem->is_klassptr()->cast_to_exactness(true); + } return (TypeAryKlassPtr*)(new TypeAryKlassPtr(ptr, elem, k, offset, not_flat, not_null_free, flat, null_free, atomic, refined_type))->hashcons(); } @@ -6876,7 +6088,7 @@ ciKlass* TypeAryPtr::klass() const { // Oops, need to compute _klass and cache it ciKlass* k_ary = compute_klass(); - if( this != TypeAryPtr::OOPS && this->dual() != TypeAryPtr::OOPS ) { + if (this != TypeAryPtr::OOPS) { // The _klass field acts as a cache of the underlying // ciKlass for this array type. In order to set the field, // we need to cast away const-ness. @@ -7001,33 +6213,37 @@ const TypeAryPtr* TypeAryKlassPtr::as_exact_instance_type(bool klass_change) con } else { el = elem(); } - bool flat, not_flat, not_null_free, atomic; + bool flat, not_flat, null_free, not_null_free, atomic; if (_refined_type) { if (_null_free && el->isa_ptr()) { el = el->is_ptr()->join_speculative(TypePtr::NOTNULL); } flat = is_flat(); not_flat = is_not_flat(); + null_free = is_null_free(); not_null_free = is_not_null_free(); atomic = is_atomic(); } else { // Unrefined types aren't trustworthy! Let's not mistake their ignorance for information. // We can always have arrays of references. Flatness is not guaranteed. flat = false; + null_free = false; // There are asserts that expect us to not be entirely naive about properties. // Only arrays of value classes can be null free. Otherwise, not_null_free == true. That is if the element type // is not an instance class, or this instance class cannot be an inline type, it's surely not null-restricted. - not_null_free = !elem()->isa_instklassptr() || !elem()->is_instklassptr()->can_be_inline_type(); + not_null_free = is_java_primitive(elem()->basic_type()) || + elem()->isa_aryklassptr() != nullptr || + (elem()->isa_instklassptr() != nullptr && !elem()->is_instklassptr()->can_be_inline_type()); bool array_can_be_flat; if (elem()->isa_instklassptr()) { FlatInArray elem_flat_in_array = elem()->is_instklassptr()->flat_in_array(); array_can_be_flat = elem_flat_in_array == MaybeFlat || elem_flat_in_array == Flat; } else { - array_can_be_flat = false; + array_can_be_flat = elem() == Type::BOTTOM; } not_flat = !array_can_be_flat; atomic = !array_can_be_flat; } - return TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(el, TypeInt::POS, false, flat, not_flat, not_null_free, atomic), k, xk, Offset(0)); + return TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(el, TypeInt::POS, false, flat, not_flat, null_free, not_null_free, atomic), k, xk, Offset(0)); } // Corresponding type for instances that subtype the given class @@ -7037,31 +6253,12 @@ const TypeAryPtr* TypeAryKlassPtr::as_subtype_instance_type(bool klass_change) c //------------------------------xmeet------------------------------------------ // Compute the MEET of two types, return a new Type object. -const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? +const Type* TypeAryKlassPtr::xmeet(const Type* t) const { + if (base() != AryKlassPtr) { + typerr(t); + } - // Current "this->_base" is Pointer switch (t->base()) { // switch on original type - - case Int: // Mixing ints & oops happens when javac - case Long: // reuses local variables - case HalfFloatTop: - case HalfFloatCon: - case HalfFloatBot: - case FloatTop: - case FloatCon: - case FloatBot: - case DoubleTop: - case DoubleCon: - case DoubleBot: - case NarrowOop: - case NarrowKlass: - case Bottom: // Ye Olde Default - return Type::BOTTOM; - case Top: - return this; - default: // All else is a mistake typerr(t); @@ -7084,135 +6281,43 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { } } - case RawPtr: - case MetadataPtr: - case OopPtr: - case AryPtr: // Meet with AryPtr - case InstPtr: // Meet with InstPtr - return TypePtr::BOTTOM; + case AryKlassPtr: + case InstKlassPtr: + return TypeJavaPtrMeetHelper::javaptr_type_xmeet(this, t->is_klassptr()); - // - // A-top } - // / | \ } Tops - // B-top A-any C-top } - // | / | \ | } Any-nulls - // B-any | C-any } - // | | | - // B-con A-con C-con } constants; not comparable across classes - // | | | - // B-not | C-not } - // | \ | / | } not-nulls - // B-bot A-not C-bot } - // \ | / } Bottoms - // A-bot } - // + } // End of switch + return this; // Return the double constant +} - case AryKlassPtr: { // Meet two KlassPtr types - const TypeAryKlassPtr *tap = t->is_aryklassptr(); - Offset off = meet_offset(tap->offset()); - const Type* elem = _elem->meet(tap->_elem); - PTR ptr = meet_ptr(tap->ptr()); - ciKlass* res_klass = nullptr; - bool res_xk = false; - bool res_flat = false; - bool res_not_flat = false; - bool res_not_null_free = false; - bool res_atomic = false; - MeetResult res = meet_aryptr(ptr, elem, this, tap, - res_klass, res_xk, res_flat, res_not_flat, res_not_null_free, res_atomic); - assert(res_xk == (ptr == Constant), ""); - bool flat = meet_flat(tap->_flat); - bool null_free = meet_null_free(tap->_null_free); - bool atomic = meet_atomic(tap->_atomic); - bool refined_type = _refined_type && tap->_refined_type; - if (res == NOT_SUBTYPE) { - flat = false; - null_free = false; - atomic = false; - refined_type = false; - } else if (res == SUBTYPE) { - if (above_centerline(tap->ptr()) && !above_centerline(this->ptr())) { - flat = _flat; - null_free = _null_free; - atomic = _atomic; - refined_type = _refined_type; - } else if (above_centerline(this->ptr()) && !above_centerline(tap->ptr())) { - flat = tap->_flat; - null_free = tap->_null_free; - atomic = tap->_atomic; - refined_type = tap->_refined_type; - } else if (above_centerline(this->ptr()) && above_centerline(tap->ptr())) { - flat = _flat || tap->_flat; - null_free = _null_free || tap->_null_free; - atomic = _atomic || tap->_atomic; - refined_type = _refined_type || tap->_refined_type; - } else if (res_xk && _refined_type != tap->_refined_type) { - // This can happen if the phi emitted by LibraryCallKit::load_default_refined_array_klass/load_non_refined_array_klass - // is processed before the typeArray guard is folded. Both inputs are constant but the input corresponding to the - // typeArray will go away. Don't constant fold it yet but wait for the control input to collapse. - ptr = PTR::NotNull; - } - } - return make(ptr, elem, res_klass, off, res_not_flat, res_not_null_free, flat, null_free, atomic, refined_type); - } // End of case KlassPtr - case InstKlassPtr: { - const TypeInstKlassPtr *tp = t->is_instklassptr(); - Offset offset = meet_offset(tp->offset()); - PTR ptr = meet_ptr(tp->ptr()); - const TypeInterfaces* interfaces = meet_interfaces(tp); - const TypeInterfaces* tp_interfaces = tp->_interfaces; - const TypeInterfaces* this_interfaces = _interfaces; +const Type* TypeAryKlassPtr::xjoin(const Type* t) const { + if (base() != AryKlassPtr) { + typerr(t); + } - switch (ptr) { - case TopPTR: - case AnyNull: // Fall 'down' to dual of object klass - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need to - // do the same here. - // - // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper(). - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && - !tp->klass_is_exact() && !tp->is_not_flat_in_array()) { - return TypeAryKlassPtr::make(ptr, _elem, _klass, offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type()); - } else { - // cannot subclass, so the meet has to fall badly below the centerline - ptr = NotNull; - interfaces = this_interfaces->intersection_with(tp->_interfaces); - FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array()); - return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array); + switch (t->base()) { + case AnyPtr: { + const TypePtr* tp = t->is_ptr(); + PTR ptr = join_ptr(tp->ptr()); + Offset offset = join_offset(tp->offset()); + switch (tp->ptr()) { + case TopPTR: + case Null: + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); + case NotNull: + case BotPTR: + return make(ptr, elem(), klass(), offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type()); + default: + typerr(t); } - case Constant: - case NotNull: - case BotPTR: { // Fall down to object klass - // LCA is object_klass, but if we subclass from the top we can do better - if (above_centerline(tp->ptr())) { - // If 'tp' is above the centerline and it is Object class - // then we can subclass in the Java class hierarchy. - // For instances when a subclass meets a superclass we fall - // below the centerline when the superclass is exact. We need - // to do the same here. - // - // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper(). - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && - !tp->klass_is_exact() && !tp->is_not_flat_in_array()) { - // that is, my array type is a subtype of 'tp' klass - return make(ptr, _elem, _klass, offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type()); - } - } - // The other case cannot happen, since t cannot be a subtype of an array. - // The meet falls down to Object class below centerline. - if (ptr == Constant) - ptr = NotNull; - interfaces = this_interfaces->intersection_with(tp_interfaces); - FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array()); - return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array); } - default: typerr(t); - } - } - } // End of switch - return this; // Return the double constant + case InstKlassPtr: + case AryKlassPtr: + return TypeJavaPtrJoinHelper::javaptr_type_xjoin(this, t->is_klassptr()); + + default: + typerr(t); + } } template bool TypePtr::is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact) { @@ -7336,12 +6441,6 @@ bool TypeAryKlassPtr::maybe_java_subtype_of_helper(const TypeKlassPtr* other, bo return TypePtr::maybe_java_subtype_of_helper_for_array(this, other, this_exact, other_exact); } -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeAryKlassPtr::xdual() const { - return new TypeAryKlassPtr(dual_ptr(), elem()->dual(), klass(), dual_offset(), !is_not_flat(), !is_not_null_free(), dual_flat(), dual_null_free(), dual_atomic(), _refined_type); -} - // Is there a single ciKlass* that can represent that type? ciKlass* TypeAryKlassPtr::exact_klass_helper() const { if (elem()->isa_klassptr()) { @@ -7462,33 +6561,6 @@ const TypeFunc* TypeFunc::make(ciMethod* method, bool is_call, bool is_osr_compi return tf; } -//------------------------------meet------------------------------------------- -// Compute the MEET of two types. It returns a new Type object. -const Type *TypeFunc::xmeet( const Type *t ) const { - // Perform a fast test for common case; meeting the same types together. - if( this == t ) return this; // Meeting same type-rep? - - // Current "this->_base" is Func - switch (t->base()) { // switch on original type - - case Bottom: // Ye Olde Default - return t; - - default: // All else is a mistake - typerr(t); - - case Top: - break; - } - return this; // Return the double constant -} - -//------------------------------xdual------------------------------------------ -// Dual: compute field-by-field dual -const Type *TypeFunc::xdual() const { - return this; -} - //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypeFunc::eq( const Type *t ) const { diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 03a641bee870..15587dc740e7 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -29,6 +29,7 @@ #include "opto/adlcVMDeps.hpp" #include "opto/compile.hpp" #include "opto/rangeinference.hpp" +#include "utilities/debug.hpp" // Portions of code courtesy of Clifford Click @@ -73,7 +74,7 @@ class TypeKlassPtr; class TypeInstKlassPtr; class TypeAryKlassPtr; class TypeMetadataPtr; -class VerifyMeet; +class VerifyMeetJoin; template class TypeIntPrototype; @@ -84,6 +85,7 @@ class TypeIntPrototype; // different kind of Type exists. Types are never modified after creation, so // all their interesting fields are constant. class Type { + friend class VerifyMeetJoinResult; public: enum TYPES { @@ -149,18 +151,18 @@ class Type { int _offset; public: - explicit Offset(int offset) : _offset(offset) {} + constexpr explicit Offset(int offset) : _offset(offset) {} const Offset meet(const Offset other) const; - const Offset dual() const; + const Offset join(const Offset other) const; const Offset add(intptr_t offset) const; - bool operator==(const Offset& other) const { + constexpr bool operator==(const Offset& other) const { return _offset == other._offset; } - bool operator!=(const Offset& other) const { + constexpr bool operator!=(const Offset& other) const { return _offset != other._offset; } - int get() const { return _offset; } + constexpr int get() const { return _offset; } void dump2(outputStream *st) const; @@ -197,29 +199,28 @@ class Type { return Compile::current()->type_dict(); } - // DUAL operation: reflect around lattice centerline. Used instead of - // join to ensure my lattice is symmetric up and down. Dual is computed - // lazily, on demand, and cached in _dual. - const Type *_dual; // Cached dual value + template + static const Type* meet_join_helper(F op, const Type* t1, const Type* t2, bool include_speculative); + const Type* meet_helper(const Type* t, bool include_speculative) const; - const Type *meet_helper(const Type *t, bool include_speculative) const; - void check_symmetrical(const Type* t, const Type* mt, const VerifyMeet& verify) const NOT_DEBUG_RETURN; + static void check_fundamental_laws(const Type* t1, const Type* t2, VerifyMeetJoin& verify) NOT_DEBUG_RETURN; + static const Type* xmeet(const Type* t1, const Type* t2); + static const Type* xjoin(const Type* t1, const Type* t2); + + // Compute meet and join, overriden by subclasses + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; protected: // Each class of type is also identified by its base. - const TYPES _base; // Enum of Types type - - Type( TYPES t ) : _dual(nullptr), _base(t) {} // Simple types - // ~Type(); // Use fast deallocation - const Type *hashcons(); // Hash-cons the type - virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; - const Type *join_helper(const Type *t, bool include_speculative) const { - assert_type_verify_empty(); - return dual()->meet_helper(t->dual(), include_speculative)->dual(); - } + const TYPES _base; // Enum of Types type - void assert_type_verify_empty() const NOT_DEBUG_RETURN; + Type(TYPES t) : _base(t) {} // Simple types + // ~Type(); // Use fast deallocation + const Type* hashcons(); // Hash-cons the type + virtual const Type* filter_helper(const Type* kills, bool include_speculative) const; + const Type* join_helper(const Type* t, bool include_speculative) const; public: @@ -258,7 +259,7 @@ class Type { return equals(meet_speculative(t), t); } - // MEET operation; lower in lattice. + // MEET operations // Variant that drops the speculative part of the types const Type *meet(const Type *t) const { return meet_helper(t, false); @@ -272,16 +273,7 @@ class Type { // NARROW: complement for widen, used by pessimistic phases virtual const Type *narrow( const Type *old ) const { return this; } - // DUAL operation: reflect around lattice centerline. Used instead of - // join to ensure my lattice is symmetric up and down. - const Type *dual() const { return _dual; } - - // Compute meet dependent on base type - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. - - // JOIN operation; higher in lattice. Done by finding the dual of the - // meet of the dual of the 2 inputs. + // JOIN operations // Variant that drops the speculative part of the types const Type *join(const Type *t) const { return join_helper(t, false); @@ -292,7 +284,7 @@ class Type { } // Modified version of JOIN adapted to the needs Node::Value. - // Normalizes all empty values to TOP. Does not kill _widen bits. + // Normalizes all empty values to TOP. Does not kill _widen bits. // Variant that drops the speculative part of the types const Type *filter(const Type *kills) const { return filter_helper(kills, false); @@ -429,7 +421,7 @@ class Type { static const char* str(const Type* t); #endif // !PRODUCT - void typerr(const Type *t) const; // Mixing types error + [[noreturn]] void typerr(const Type *t) const; // Mixing types error // Create basic type static const Type* get_const_basic_type(BasicType type) { @@ -533,6 +525,9 @@ class Type { static const Type* _const_basic_type[T_CONFLICT+1]; }; +inline constexpr Type::Offset Type::Offset::top(Type::OffsetTop); +inline constexpr Type::Offset Type::Offset::bottom(Type::OffsetBot); + //------------------------------TypeF------------------------------------------ // Class of Float-Constant Types. class TypeF : public Type { @@ -550,8 +545,8 @@ class TypeF : public Type { virtual bool is_finite() const; // Has a finite value virtual bool is_nan() const; // Is not a number (NaN) - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; // Convenience common pre-built types. static const TypeF *MAX; static const TypeF *MIN; @@ -583,7 +578,7 @@ class TypeH : public Type { virtual float getf() const; virtual const Type* xmeet(const Type* t) const; - virtual const Type* xdual() const; // Compute dual right now. + virtual const Type* xjoin(const Type* t) const; // Convenience common pre-built types. static const TypeH* MAX; static const TypeH* MIN; @@ -613,8 +608,8 @@ class TypeD : public Type { virtual bool is_finite() const; // Has a finite value virtual bool is_nan() const; // Is not a number (NaN) - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; // Convenience common pre-built types. static const TypeD *MAX; static const TypeD *MIN; @@ -629,12 +624,7 @@ class TypeD : public Type { class TypeInteger : public Type { protected: - TypeInteger(TYPES t, int w, bool dual) : Type(t), _is_dual(dual), _widen(w) {} - - // Denote that a set is a dual set. - // Dual sets are only used to compute the join of 2 sets, and not used - // outside. - const bool _is_dual; + TypeInteger(TYPES t, int w) : Type(t), _widen(w) {} public: const short _widen; // Limit on times we widen this sucker @@ -800,8 +790,7 @@ class TypeInteger : public Type { */ class TypeInt : public TypeInteger { private: - TypeInt(const TypeIntPrototype& t, int w, bool dual); - static const Type* make_or_top(const TypeIntPrototype& t, int widen, bool dual); + TypeInt(const TypeIntPrototype& t, int w); friend class TypeIntHelper; @@ -828,7 +817,7 @@ class TypeInt : public TypeInteger { static const Type* make_or_top(const TypeIntPrototype& t, int widen); static const TypeInt* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_int(); } static const TypeInt* make(const TypeIntMirror& t, int widen) { - return (new TypeInt(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_int(); + return (new TypeInt(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen))->hashcons()->is_int(); } // Check for single integer @@ -848,7 +837,7 @@ class TypeInt : public TypeInteger { virtual bool is_finite() const; // Has a finite value virtual const Type* xmeet(const Type* t) const; - virtual const Type* xdual() const; // Compute dual right now. + virtual const Type* xjoin(const Type* t) const; virtual const Type* widen(const Type* t, const Type* limit_type) const; virtual const Type* narrow(const Type* t) const; @@ -891,8 +880,7 @@ class TypeInt : public TypeInteger { // Similar to TypeInt class TypeLong : public TypeInteger { private: - TypeLong(const TypeIntPrototype& t, int w, bool dual); - static const Type* make_or_top(const TypeIntPrototype& t, int widen, bool dual); + TypeLong(const TypeIntPrototype& t, int w); friend class TypeIntHelper; @@ -920,7 +908,7 @@ class TypeLong : public TypeInteger { static const Type* make_or_top(const TypeIntPrototype& t, int widen); static const TypeLong* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_long(); } static const TypeLong* make(const TypeIntMirror& t, int widen) { - return (new TypeLong(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen, false))->hashcons()->is_long(); + return (new TypeLong(TypeIntPrototype{{t._lo, t._hi}, {t._ulo, t._uhi}, t._bits}, widen))->hashcons()->is_long(); } // Check for single integer @@ -946,7 +934,7 @@ class TypeLong : public TypeInteger { virtual jlong lo_as_long() const { return _lo; } virtual const Type* xmeet(const Type* t) const; - virtual const Type* xdual() const; // Compute dual right now. + virtual const Type* xjoin(const Type* t) const; virtual const Type* widen(const Type* t, const Type* limit_type) const; virtual const Type* narrow(const Type* t) const; // Convenience common pre-built types. @@ -1007,8 +995,8 @@ class TypeTuple : public Type { // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly static const Type **fields( uint arg_cnt ); - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; // Convenience common pre-built types. static const TypeTuple *IFBOTH; static const TypeTuple *IFFALSE; @@ -1030,8 +1018,8 @@ class TypeTuple : public Type { //------------------------------TypeAry---------------------------------------- // Class of Array Types class TypeAry : public Type { - TypeAry(const Type* elem, const TypeInt* size, bool stable, bool flat, bool not_flat, bool not_null_free, bool atomic) : Type(Array), - _elem(elem), _size(size), _stable(stable), _flat(flat), _not_flat(not_flat), _not_null_free(not_null_free), _atomic(atomic) {} + TypeAry(const Type* elem, const TypeInt* size, bool stable, bool flat, bool not_flat, bool null_free, bool not_null_free, bool atomic) : Type(Array), + _elem(elem), _size(size), _stable(stable), _flat(flat), _not_flat(not_flat), _null_free(null_free), _not_null_free(not_null_free), _atomic(atomic) {} public: virtual bool eq( const Type *t ) const; virtual uint hash() const; // Type specific hashing @@ -1046,6 +1034,7 @@ class TypeAry : public Type { // Inline type array properties const bool _flat; // Array is flat const bool _not_flat; // Array is never flat + const bool _null_free; // Array is null-free const bool _not_null_free; // Array is never null-free const bool _atomic; // Array is atomic @@ -1053,10 +1042,10 @@ class TypeAry : public Type { public: static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable, - bool flat, bool not_flat, bool not_null_free, bool atomic); + bool flat, bool not_flat, bool null_free, bool not_null_free, bool atomic); - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const { ShouldNotReachHere(); } + virtual const Type* xjoin(const Type* t) const { ShouldNotReachHere(); } bool ary_must_be_exact() const; // true if arrays of such are never generic virtual const TypeAry* remove_speculative() const; virtual const Type* cleanup_speculative() const; @@ -1090,9 +1079,6 @@ class TypeVect : public Type { static const TypeVect* make(const BasicType elem_bt, uint length, bool is_mask = false); static const TypeVect* makemask(const BasicType elem_bt, uint length); - virtual const Type* xmeet( const Type *t) const; - virtual const Type* xdual() const; // Compute dual right now. - static const TypeVect* VECTA; static const TypeVect* VECTS; static const TypeVect* VECTD; @@ -1179,7 +1165,6 @@ class TypeInterfaces : public Type { bool eq(ciInstanceKlass* k) const; bool is_subset(ciInstanceKlass* k) const; uint hash() const; - const Type *xdual() const; void dump(outputStream* st) const; const TypeInterfaces* union_with(const TypeInterfaces* other) const; const TypeInterfaces* intersection_with(const TypeInterfaces* other) const; @@ -1194,8 +1179,6 @@ class TypeInterfaces : public Type { static int compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& k2); static int compare(ciInstanceKlass** k1, ciInstanceKlass** k2); - const Type* xmeet(const Type* t) const; - bool singleton(void) const; bool has_non_array_interface() const; }; @@ -1214,19 +1197,8 @@ class TypePtr : public Type { public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; - // Only applies to TypeInstPtr and TypeInstKlassPtr. Since the common super class is TypePtr, it is defined here. - // - // FlatInArray defines the following Boolean Lattice structure - // - // TopFlat - // / \ - // Flat NotFlat - // \ / - // MaybeFlat - // - // with meet (see TypePtr::meet_flat_in_array()) and join (implemented over dual, see TypePtr::flat_in_array_dual) enum FlatInArray { - TopFlat, // Dedicated top element and dual of MaybeFlat. Result when joining Flat and NotFlat. + TopFlat, // Dedicated top element. Result when joining Flat and NotFlat. Flat, // An instance is always flat in an array. NotFlat, // An instance is never flat in an array. MaybeFlat, // We don't know whether an instance is flat in an array. @@ -1237,13 +1209,16 @@ class TypePtr : public Type { relocInfo::relocType reloc, const TypePtr* speculative = nullptr, int inline_depth = InlineDepthBottom) : - Type(t), _speculative(speculative), _inline_depth(inline_depth), _offset(offset), - _ptr(ptr), _reloc(reloc) {} + Type(t), _speculative(speculative), _inline_depth(inline_depth), _offset(offset), _ptr(ptr), _reloc(reloc) { + assert(t == AnyPtr || (ptr != TopPTR && ptr != Null), "Top and Null must be AnyPtr"); + assert(ptr != AnyNull, "Nonsensical PTR"); + assert(ptr == TopPTR || offset != Offset::top, "only TopPTR can have top offset"); + assert(static_cast(ptr) < static_cast(lastPTR), "out of bounds"); + } static const PTR ptr_meet[lastPTR][lastPTR]; static const PTR ptr_dual[lastPTR]; static const char * const ptr_msg[lastPTR]; - static const FlatInArray flat_in_array_dual[Uninitialized]; static const char* const flat_in_array_msg[Uninitialized]; enum { @@ -1263,51 +1238,29 @@ class TypePtr : public Type { int _inline_depth; // utility methods to work on the speculative part of the type - const TypePtr* dual_speculative() const; const TypePtr* xmeet_speculative(const TypePtr* other) const; + const TypePtr* xjoin_speculative(const TypePtr* other) const; bool eq_speculative(const TypePtr* other) const; int hash_speculative() const; const TypePtr* add_offset_speculative(intptr_t offset) const; const TypePtr* with_offset_speculative(intptr_t offset) const; // utility methods to work on the inline depth of the type - int dual_inline_depth() const; int meet_inline_depth(int depth) const; - + int join_inline_depth(int depth) const; #ifndef PRODUCT void dump_speculative(outputStream* st) const; void dump_inline_depth(outputStream* st) const; void dump_offset(outputStream* st) const; #endif - // TypeInstPtr (TypeAryPtr resp.) and TypeInstKlassPtr (TypeAryKlassPtr resp.) implement very similar meet logic. - // The logic for meeting 2 instances (2 arrays resp.) is shared in the 2 utility methods below. However the logic for - // the oop and klass versions can be slightly different and extra logic may have to be executed depending on what - // exact case the meet falls into. The MeetResult struct is used by the utility methods to communicate what case was - // encountered so the right logic specific to klasses or oops can be executed., - enum MeetResult { - QUICK, - UNLOADED, - SUBTYPE, - NOT_SUBTYPE, - LCA - }; - template static TypePtr::MeetResult meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type, - const T* other_type, ciKlass*& res_klass, bool& res_xk); - protected: - static FlatInArray meet_flat_in_array(FlatInArray left, FlatInArray other); - - template static MeetResult meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary, - ciKlass*& res_klass, bool& res_xk, bool &res_flat, bool &res_not_flat, bool &res_not_null_free, bool &res_atomic); - template static bool is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact); template static bool is_same_java_type_as_helper_for_instance(const T1* this_one, const T2* other); template static bool maybe_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact); template static bool is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact); template static bool is_same_java_type_as_helper_for_array(const T1* this_one, const T2* other); template static bool maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact); - template static bool is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk); - template static bool is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk); + public: const Offset _offset; // Offset into oop, with TOP & BOT const PTR _ptr; // Pointer equivalence class @@ -1336,13 +1289,14 @@ class TypePtr : public Type { virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xmeet_helper( const Type *t ) const; + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xmeet_helper(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; + virtual const Type* xjoin_helper(const Type* t) const; Offset meet_offset(int offset) const; - Offset dual_offset() const; - virtual const Type *xdual() const; // Compute dual right now. + Offset join_offset(int offset) const; - // meet, dual and join over pointer equivalence sets + // meet and join over pointer equivalence sets PTR meet_ptr( const PTR in_ptr ) const { return ptr_meet[in_ptr][ptr()]; } PTR dual_ptr() const { return ptr_dual[ptr()]; } @@ -1419,8 +1373,8 @@ class TypeRawPtr : public TypePtr { virtual const TypePtr* add_offset(intptr_t offset) const; virtual const TypeRawPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return nullptr;} - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; // Convenience common pre-built types. static const TypeRawPtr *BOTTOM; static const TypeRawPtr *NOTNULL; @@ -1447,6 +1401,13 @@ class TypeOopPtr : public TypePtr { InstanceTop = -1, // undefined instance InstanceBot = 0 // any possible instance }; + + static constexpr bool is_oopptr_type = true; + using ciEnv = ::ciEnv; + using PtrType = TypePtr; + using InstType = TypeInstPtr; + using AryType = TypeAryPtr; + protected: // Oop is null, unless this is a constant oop. @@ -1470,10 +1431,11 @@ class TypeOopPtr : public TypePtr { static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling); - int dual_instance_id() const; int meet_instance_id(int uid) const; + int join_instance_id(int uid) const; const TypeInterfaces* meet_interfaces(const TypeOopPtr* other) const; + const TypeInterfaces* join_interfaces(const TypeOopPtr* other) const; // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -1539,8 +1501,9 @@ class TypeOopPtr : public TypePtr { ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != nullptr || maybe_null, ""); return k; } ciKlass* unloaded_klass() const { assert(!is_loaded(), "only for unloaded types"); return klass(); } - virtual bool is_loaded() const { return klass()->is_loaded(); } - virtual bool klass_is_exact() const { return _klass_is_exact; } + virtual bool is_loaded() const { return klass()->is_loaded(); } + virtual bool klass_is_exact() const { return _klass_is_exact; } + const TypeInterfaces* interfaces() const { return _interfaces; } // Returns true if this pointer points at memory which contains a // compressed oop references. @@ -1586,9 +1549,9 @@ class TypeOopPtr : public TypePtr { virtual const TypePtr* with_instance_id(int instance_id) const; - virtual const Type *xdual() const; // Compute dual right now. // the core of the computation of the meet for TypeOopPtr and for its subclasses - virtual const Type *xmeet_helper(const Type *t) const; + virtual const Type* xmeet_helper(const Type* t) const; + virtual const Type* xjoin_helper(const Type* t) const; // Convenience common pre-built type. static const TypeOopPtr *BOTTOM; @@ -1596,18 +1559,6 @@ class TypeOopPtr : public TypePtr { virtual void dump2( Dict &d, uint depth, outputStream *st ) const; #endif private: - virtual bool is_meet_subtype_of(const TypePtr* other) const { - return is_meet_subtype_of_helper(other->is_oopptr(), klass_is_exact(), other->is_oopptr()->klass_is_exact()); - } - - virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const { - ShouldNotReachHere(); return false; - } - - virtual const TypeInterfaces* interfaces() const { - return _interfaces; - }; - const TypeOopPtr* is_reference_type(const Type* other) const { return other->isa_oopptr(); } @@ -1716,14 +1667,9 @@ class TypeInstPtr : public TypeOopPtr { virtual const TypeInstPtr* cast_to_maybe_flat_in_array() const; virtual FlatInArray flat_in_array() const { return _flat_in_array; } - FlatInArray dual_flat_in_array() const { - return flat_in_array_dual[_flat_in_array]; - } - // the core of the computation of the meet of 2 types - virtual const Type *xmeet_helper(const Type *t) const; - virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet_helper(const Type* t) const; + virtual const Type* xjoin_helper(const Type* t) const; const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const; @@ -1740,8 +1686,6 @@ class TypeInstPtr : public TypeOopPtr { #endif private: - virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const; - virtual bool is_meet_same_type_as(const TypePtr* other) const { return _klass->equals(other->is_instptr()->_klass) && _interfaces->eq(other->is_instptr()->_interfaces); } @@ -1755,6 +1699,8 @@ class TypeAryPtr : public TypeOopPtr { friend class TypePtr; friend class TypeInstPtr; friend class TypeInterfaces; + friend class TypeJavaPtrMeetHelper; + friend class TypeJavaPtrJoinHelper; TypeAryPtr(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset, int instance_id, bool is_autobox_cache, @@ -1782,8 +1728,6 @@ class TypeAryPtr : public TypeOopPtr { // the array has its own memory slice so we need to keep track of // which field is accessed const Offset _field_offset; - Offset meet_field_offset(const Type::Offset offset) const; - Offset dual_field_offset() const; ciKlass* compute_klass() const; @@ -1814,7 +1758,7 @@ class TypeAryPtr : public TypeOopPtr { // Inline type array properties bool is_flat() const { return _ary->_flat; } bool is_not_flat() const { return _ary->_not_flat; } - bool is_null_free() const { return _ary->_elem->make_ptr() != nullptr && (_ary->_elem->make_ptr()->ptr() == NotNull || _ary->_elem->make_ptr()->ptr() == AnyNull); } + bool is_null_free() const { return _ary->_null_free; } bool is_not_null_free() const { return _ary->_not_null_free; } bool is_atomic() const { return _ary->_atomic; } @@ -1855,8 +1799,8 @@ class TypeAryPtr : public TypeOopPtr { virtual const TypePtr* with_instance_id(int instance_id) const; // the core of the computation of the meet of 2 types - virtual const Type *xmeet_helper(const Type *t) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet_helper(const Type* t) const; + virtual const Type* xjoin_helper(const Type* t) const; // Inline type array properties const TypeAryPtr* cast_to_flat(bool flat) const; @@ -1909,8 +1853,6 @@ class TypeAryPtr : public TypeOopPtr { #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping #endif -private: - virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const; }; //------------------------------TypeMetadataPtr------------------------------------- @@ -1940,8 +1882,8 @@ class TypeMetadataPtr : public TypePtr { virtual const TypePtr *add_offset( intptr_t offset ) const; - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; virtual intptr_t get_con() const; @@ -1969,11 +1911,18 @@ class TypeKlassPtr : public TypePtr { virtual uint hash() const; virtual bool singleton(void) const; // TRUE if type is a singleton + static constexpr bool is_oopptr_type = false; + using ciEnv = ::ciEnv; + using PtrType = TypePtr; + using InstType = TypeInstKlassPtr; + using AryType = TypeAryKlassPtr; + protected: ciKlass* _klass; const TypeInterfaces* _interfaces; const TypeInterfaces* meet_interfaces(const TypeKlassPtr* other) const; + const TypeInterfaces* join_interfaces(const TypeKlassPtr* other) const; virtual bool must_be_exact() const { ShouldNotReachHere(); return false; } virtual ciKlass* exact_klass_helper() const; virtual ciKlass* klass() const { return _klass; } @@ -2011,9 +1960,9 @@ class TypeKlassPtr : public TypePtr { // corresponding pointer to instances which subtype a given class virtual const TypeOopPtr* as_subtype_instance_type(bool klass_change = true) const = 0; - virtual const TypePtr *add_offset( intptr_t offset ) const { ShouldNotReachHere(); return nullptr; } - virtual const Type *xmeet( const Type *t ) const { ShouldNotReachHere(); return nullptr; } - virtual const Type *xdual() const { ShouldNotReachHere(); return nullptr; } + virtual const TypePtr* add_offset(intptr_t offset) const { ShouldNotReachHere(); return nullptr; } + virtual const Type* xmeet(const Type* t) const { ShouldNotReachHere(); return nullptr; } + virtual const Type* xjoin(const Type* t) const { ShouldNotReachHere(); return nullptr; } virtual intptr_t get_con() const; @@ -2023,19 +1972,11 @@ class TypeKlassPtr : public TypePtr { virtual const TypeKlassPtr* try_improve() const { return this; } -private: - virtual bool is_meet_subtype_of(const TypePtr* other) const { - return is_meet_subtype_of_helper(other->is_klassptr(), klass_is_exact(), other->is_klassptr()->klass_is_exact()); - } - - virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const { - ShouldNotReachHere(); return false; - } - - virtual const TypeInterfaces* interfaces() const { + const TypeInterfaces* interfaces() const { return _interfaces; }; +private: const TypeKlassPtr* is_reference_type(const Type* other) const { return other->isa_klassptr(); } @@ -2103,18 +2044,14 @@ class TypeInstKlassPtr : public TypeKlassPtr { virtual bool empty() const; virtual const TypePtr *add_offset( intptr_t offset ) const; - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; virtual const TypeInstKlassPtr* with_offset(intptr_t offset) const; virtual const TypeKlassPtr* try_improve() const; virtual FlatInArray flat_in_array() const { return _flat_in_array; } - FlatInArray dual_flat_in_array() const { - return flat_in_array_dual[_flat_in_array]; - } - virtual bool can_be_inline_array() const; // Convenience common pre-built types. @@ -2124,9 +2061,6 @@ class TypeInstKlassPtr : public TypeKlassPtr { #ifndef PRODUCT virtual void dump2(Dict& d, uint depth, outputStream* st) const; #endif // PRODUCT - -private: - virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const; }; // Array klass pointer, mirrors TypeAryPtr @@ -2134,6 +2068,8 @@ class TypeAryKlassPtr : public TypeKlassPtr { friend class TypeInstKlassPtr; friend class Type; friend class TypePtr; + friend class TypeJavaPtrMeetHelper; + friend class TypeJavaPtrJoinHelper; const Type *_elem; const bool _not_flat; // Array is never flat @@ -2155,30 +2091,6 @@ class TypeAryKlassPtr : public TypeKlassPtr { virtual bool must_be_exact() const; - bool dual_flat() const { - return _flat; - } - - bool meet_flat(bool other) const { - return _flat && other; - } - - bool dual_null_free() const { - return _null_free; - } - - bool meet_null_free(bool other) const { - return _null_free && other; - } - - bool dual_atomic() const { - return _atomic; - } - - bool meet_atomic(bool other) const { - return _atomic && other; - } - public: // returns base element type, an instance klass (and not interface) for object arrays @@ -2212,9 +2124,9 @@ class TypeAryKlassPtr : public TypeKlassPtr { virtual const TypeAryPtr* as_exact_instance_type(bool klass_change = true) const; virtual const TypeAryPtr* as_subtype_instance_type(bool klass_change = true) const; - virtual const TypePtr *add_offset( intptr_t offset ) const; - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. + virtual const TypePtr* add_offset(intptr_t offset) const; + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xjoin(const Type* t) const; virtual const TypeAryKlassPtr* with_offset(intptr_t offset) const; @@ -2237,8 +2149,6 @@ class TypeAryKlassPtr : public TypeKlassPtr { #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping #endif -private: - virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const; }; class TypeNarrowPtr : public Type { @@ -2263,9 +2173,6 @@ class TypeNarrowPtr : public Type { virtual uint hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. - virtual intptr_t get_con() const; virtual bool empty(void) const; // TRUE if type is vacuous @@ -2414,9 +2321,6 @@ class TypeFunc : public Type { bool scalarized_return = false); static const TypeFunc *make(const TypeTuple* domain, const TypeTuple* range); - virtual const Type *xmeet( const Type *t ) const; - virtual const Type *xdual() const; // Compute dual right now. - BasicType return_type() const; bool returns_inline_type_as_fields() const { diff --git a/src/hotspot/share/opto/typejavaptr.hpp b/src/hotspot/share/opto/typejavaptr.hpp new file mode 100644 index 000000000000..8c964cd77757 --- /dev/null +++ b/src/hotspot/share/opto/typejavaptr.hpp @@ -0,0 +1,818 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OPTO_TYPEJAVAPTR_HPP +#define SHARE_OPTO_TYPEJAVAPTR_HPP + +#include "cppstdlib/type_traits.hpp" +#include "opto/type.hpp" + +class TypeJavaPtrMeetHelper { +private: + friend class TypeJavaPtrJoinHelper; + +public: + template + static const PtrType* javaptr_type_xmeet(const PtrType* t1, const PtrType* t2) { + if (t1 == t2) { + return t1; + } + + TypePtr::PTR ptr1 = t1->ptr(); + TypePtr::PTR ptr2 = t2->ptr(); + assert(ptr1 == TypePtr::Constant || ptr1 == TypePtr::NotNull || ptr1 == TypePtr::BotPTR, "unexpected ptr: %d", int(ptr1)); + assert(ptr2 == TypePtr::Constant || ptr2 == TypePtr::NotNull || ptr2 == TypePtr::BotPTR, "unexpected ptr: %d", int(ptr2)); + + if constexpr (PtrType::is_oopptr_type) { + return oopptr_type_xmeet(t1, t2); + } else { + return klassptr_type_xmeet(t1, t2); + } + } + +private: + template + static const OopType* oopptr_type_xmeet(const OopType* t1, const OopType* t2) { + assert(t1 != t2, "must have been handled"); + Type::TYPES base1 = t1->base(); + Type::TYPES base2 = t2->base(); + assert(base1 == Type::InstPtr || base1 == Type::AryPtr, "must be an oopptr: %d", int(base1)); + assert(base2 == Type::InstPtr || base2 == Type::AryPtr, "must be an oopptr: %d", int(base2)); + + Type::Offset offset = meet_offset(t1, t2); + auto interfaces = meet_interfaces(t1, t2); + auto flat_in_array = meet_flat_in_array(t1, t2); + int instance_id = meet_instance_id(t1, t2); + auto speculative = meet_speculative(t1, t2); + int inline_depth = meet_inline_depth(t1, t2); + + if (base1 != base2) { + TypePtr::PTR ptr = t1->ptr() == TypePtr::BotPTR || t2->ptr() == TypePtr::BotPTR ? TypePtr::BotPTR : TypePtr::NotNull; + return OopType::InstType::make(ptr, OopType::ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, + flat_in_array, instance_id, speculative, inline_depth); + } else if (base1 == Type::InstPtr) { + return instptr_type_xmeet(t1->is_instptr(), t2->is_instptr(), offset, interfaces, flat_in_array, instance_id, speculative, inline_depth); + } else { + return aryptr_type_xmeet(t1->is_aryptr(), t2->is_aryptr(), offset, instance_id, speculative, inline_depth); + } + } + + template + static const InstOopType* instptr_type_xmeet(const InstOopType* t1, const InstOopType* t2, Type::Offset offset, InterfacesType interfaces, + TypePtr::FlatInArray flat_in_array, int instance_id, const PtrType* speculative, int inline_depth) { + using ConstOopType = decltype(t1->const_oop()); + + auto k1 = t1->instance_klass(); + auto k2 = t2->instance_klass(); + TypePtr::PTR ptr; + ConstOopType const_oop = nullptr; + meet_ptr_and_const_oop(ptr, const_oop, t1, t2); + bool xk = t1->klass_is_exact() && t2->klass_is_exact() && k1 == k2; + + // Consider an unloaded class to be a direct child of j.l.O and not have any subclass + decltype(k1) k; + if (k1 == k2) { + k = k1; + } else if (k1->is_java_lang_Object() || k2->is_java_lang_Object() || !k1->is_loaded() || !k2->is_loaded()) { + k = InstOopType::ciEnv::current()->Object_klass(); + } else { + k = k1->least_common_ancestor(k2)->as_instance_klass(); + } + + return InstOopType::make(ptr, k, interfaces, xk, const_oop, offset, flat_in_array, instance_id, speculative, inline_depth); + } + + template + static const AryOopType* aryptr_type_xmeet(const AryOopType* t1, const AryOopType* t2, Type::Offset offset, int instance_id, + const PtrType* speculative, int inline_depth) { + using AryType = std::remove_pointer_tary())>; + using ConstOopType = decltype(t1->const_oop()); + using ElemType = decltype(t1->elem()); + using KlassType = decltype(t1->klass()); + + TypePtr::PTR ptr; + ConstOopType const_oop = nullptr; + meet_ptr_and_const_oop(ptr, const_oop, t1, t2); + + ElemType elem; + KlassType klass = nullptr; + meet_ary_elem(elem, klass, t1, t2); + + auto size = t1->size()->meet(t2->size())->is_int(); + bool stable = t1->is_stable() && t2->is_stable(); + bool flat = t1->is_flat() && t2->is_flat(); + bool not_flat = t1->is_not_flat() && t2->is_not_flat(); + bool null_free = t1->is_null_free() && t2->is_null_free(); + bool not_null_free = t1->is_not_null_free() && t2->is_not_null_free(); + bool atomic = t1->is_atomic() && t2->is_atomic(); + auto ary = AryType::make(elem, size, stable, flat, not_flat, null_free, not_null_free, atomic); + bool xk = t1->klass_is_exact() && t2->klass_is_exact() && !aryptr_klass_disjoint(t1, t2); + auto field_offset = t1->field_offset().meet(t2->field_offset()); + bool autobox_cache = t1->is_autobox_cache() && t2->is_autobox_cache(); + return AryOopType::make(ptr, const_oop, ary, klass, xk, offset, field_offset, instance_id, speculative, inline_depth, autobox_cache); + } + + template + static const KlassType* klassptr_type_xmeet(const KlassType* t1, const KlassType* t2) { + assert(t1 != t2, "must have been handled"); + Type::TYPES base1 = t1->base(); + Type::TYPES base2 = t2->base(); + assert(base1 == Type::InstKlassPtr || base1 == Type::AryKlassPtr, "must be a klassptr: %d", int(base1)); + assert(base2 == Type::InstKlassPtr || base2 == Type::AryKlassPtr, "must be a klassptr: %d", int(base2)); + + Type::Offset offset = meet_offset(t1, t2); + auto interfaces = meet_interfaces(t1, t2); + auto flat_in_array = meet_flat_in_array(t1, t2); + + if (base1 != base2) { + TypePtr::PTR ptr = t1->ptr() == TypePtr::BotPTR || t2->ptr() == TypePtr::BotPTR ? TypePtr::BotPTR : TypePtr::NotNull; + return KlassType::InstType::make(ptr, KlassType::ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array); + } else if (base1 == Type::InstKlassPtr) { + return instklassptr_type_xmeet(t1->is_instklassptr(), t2->is_instklassptr(), offset, interfaces, flat_in_array); + } else { + return aryklassptr_type_xmeet(t1->is_aryklassptr(), t2->is_aryklassptr(), offset); + } + } + + template + static const InstKlassType* instklassptr_type_xmeet(const InstKlassType* t1, const InstKlassType* t2, Type::Offset offset, InterfacesType interfaces, + TypePtr::FlatInArray flat_in_array) { + TypePtr::PTR ptr = meet_inst_klass_ptr(t1, t2); + auto klass = t1->instance_klass()->least_common_ancestor(t2->instance_klass())->as_instance_klass(); + return InstKlassType::make(ptr, klass, interfaces, offset, flat_in_array); + } + + template + static const AryKlassType* aryklassptr_type_xmeet(const AryKlassType* t1, const AryKlassType* t2, Type::Offset offset) { + using ElemType = decltype(t1->elem()); + using KlassType = decltype(t1->klass()); + + TypePtr::PTR ptr = meet_ary_klass_ptr(t1, t2); + ElemType elem; + KlassType klass = nullptr; + meet_ary_elem(elem, klass, t1, t2); + bool not_flat = t1->is_not_flat() && t2->is_not_flat(); + bool not_null_free = t1->is_not_null_free() && t2->is_not_null_free(); + bool flat = t1->is_flat() && t2->is_flat(); + bool null_free = t1->is_null_free() && t2->is_null_free(); + bool atomic = t1->is_atomic() && t2->is_atomic(); + bool refined = t1->is_refined_type() && t2->is_refined_type(); + return AryKlassType::make(ptr, elem, klass, offset, not_flat, not_null_free, flat, null_free, atomic, refined); + } + + template + static Type::Offset meet_offset(const PtrType* t1, const PtrType* t2) { + return Type::Offset(t1->offset()).meet(Type::Offset(t2->offset())); + } + + template > + static InterfacesType meet_interfaces(const PtrType* t1, const PtrType* t2) { + return t1->interfaces()->intersection_with(t2->interfaces()); + } + + template + static int meet_instance_id(const OopType* t1, const OopType* t2) { + int id1 = t1->instance_id(); + int id2 = t2->instance_id(); + assert(id1 != TypeOopPtr::InstanceTop && id2 != TypeOopPtr::InstanceTop, "InstanceTop must be normalized to TypePtr::TopPTR"); + return id1 == id2 ? id1 : TypeOopPtr::InstanceBot; + } + + template + static auto meet_speculative(const OopType* t1, const OopType* t2) { + auto s1 = t1->speculative(); + auto s2 = t2->speculative(); + if (s1 == nullptr && s2 == nullptr) { + return s1; + } + + if (s1 == nullptr) { + s1 = t1; + } else if (s2 == nullptr) { + s2 = t2; + } + return s1->meet(s2)->is_ptr(); + } + + template + static int meet_inline_depth(const OopType* t1, const OopType* t2) { + return MAX2(t1->inline_depth(), t2->inline_depth()); + } + + template + static void meet_ptr_and_const_oop(TypePtr::PTR& ptr, ConstOopType& const_oop, const OopType* t1, const OopType* t2) { + if (t1->ptr() == TypePtr::Constant && t2->ptr() == TypePtr::Constant && t1->const_oop() == t2->const_oop()) { + ptr = TypePtr::Constant; + const_oop = t1->const_oop(); + } else if (t1->ptr() != TypePtr::BotPTR && t2->ptr() != TypePtr::BotPTR) { + ptr = TypePtr::NotNull; + } else { + ptr = TypePtr::BotPTR; + } + } + + template + static TypePtr::PTR meet_inst_klass_ptr(const InstKlassType* t1, const InstKlassType* t2) { + if (t1->ptr() == TypePtr::Constant && t2->ptr() == TypePtr::Constant && + t1->instance_klass() == t2->instance_klass() && t1->interfaces() == t2->interfaces()) { + return TypePtr::Constant; + } else if (t1->ptr() != TypePtr::BotPTR && t2->ptr() != TypePtr::BotPTR) { + return TypePtr::NotNull; + } else { + return TypePtr::BotPTR; + } + } + + template + static TypePtr::PTR meet_ary_klass_ptr(const AryKlassType* t1, const AryKlassType* t2) { + if (t1->ptr() == TypePtr::Constant && t2->ptr() == TypePtr::Constant && + t1->elem() == t2->elem() && t1->klass() == t2->klass() && + t1->is_not_flat() == t2->is_not_flat() && t1->is_not_null_free() == t2->is_not_null_free() && + t1->is_flat() == t2->is_flat() && t1->is_null_free() == t2->is_null_free() && + t1->is_atomic() == t2->is_atomic() && t1->is_refined_type() == t2->is_refined_type()) { + return TypePtr::Constant; + } else if (t1->ptr() != TypePtr::BotPTR && t2->ptr() != TypePtr::BotPTR) { + return TypePtr::NotNull; + } else { + return TypePtr::BotPTR; + } + } + + template + static TypePtr::FlatInArray meet_flat_in_array(const PtrType* t1, const PtrType* t2) { + auto v1 = t1->flat_in_array(); + auto v2 = t2->flat_in_array(); + assert(v1 != TypePtr::TopFlat && v2 != TypePtr::TopFlat, "TopFlat must be normalized to TypePtr::TopPTR"); + return v1 == v2 ? v1 : TypePtr::MaybeFlat; + } + + template + static void meet_ary_elem(const ElemType*& elem, CIKlassType& klass, const AryType* t1, const AryType* t2) { + const ElemType* elem1 = t1->elem(); + const ElemType* elem2 = t2->elem(); + assert(!elem1->empty() && !elem2->empty(), "cannot be top"); + if (elem1->base() == elem2->base()) { + if (elem1->base() == Type::Int) { + // boolean[], byte[], short[], char[], int[] all use some kinds of TypeInt as their element + // types, klass is used to distinguish between them. As a result, different kinds of array + // should result in bot[]. + CIKlassType klass1 = t1->klass(); + CIKlassType klass2 = t2->klass(); + assert(klass1 != nullptr && klass2 != nullptr, "ambiguous array"); + if (klass1 == klass2) { + elem = elem1->meet_speculative(elem2); + klass = klass1; + } else { + elem = ElemType::BOTTOM; + } + } else { + elem = elem1->meet_speculative(elem2); + } + } else { + if (elem1->make_ptr() != nullptr && elem2->make_ptr() != nullptr) { + elem = elem1->meet_speculative(elem2); + } else { + elem = ElemType::BOTTOM; + } + } + } + + // TypeAryPtr is tricky, an exact Number[][] and an exact Integer[][] should be disjoint. + // However, their elements are non-exact Number[] and exact Integer[], respectively, which are + // not disjoint. This function specifically handle those cases. + template + static bool aryptr_klass_disjoint(const AryOopType* t1, const AryOopType* t2) { + if (!t1->klass_is_exact() && !t2->klass_is_exact()) { + // If t1 and t2 are both non-exact and disjoint, their elems should be disjoint, too. As a + // result, we do not need to handle that case here. + return false; + } + + decltype(t1->is_oopptr()) exact_type; + decltype(t1->is_oopptr()) other_type; + bool both_are_exact; + if (t1->klass_is_exact()) { + exact_type = t1; + other_type = t2; + both_are_exact = t2->klass_is_exact(); + } else { + exact_type = t2; + other_type = t1; + both_are_exact = t1->klass_is_exact(); + } + + // At each iteration, walk down from the array klasses to their element types. Keep + // both_are_exact because the element type of an exact Number[][] is a non-exact Number[], but + // we need to remember that the original type is an exact array. + while (true) { + if (exact_type->base() == Type::InstPtr) { + if (other_type->base() == Type::AryPtr) { + return true; + } + + auto exact_klass = exact_type->is_instptr()->instance_klass(); + auto other_klass = other_type->is_instptr()->instance_klass(); + if (both_are_exact) { + return exact_klass != other_klass || exact_type->interfaces() != other_type->interfaces(); + } else { + return !exact_klass->is_subtype_of(other_klass) || !exact_type->interfaces()->contains(other_type->interfaces()); + } + } + + if (other_type->base() == Type::InstPtr) { + auto other_inst_type = other_type->is_instptr(); + return both_are_exact || !other_inst_type->instance_klass()->is_java_lang_Object() || + !AryOopType::_array_interfaces->contains(other_inst_type->interfaces()); + } + + auto exact_ary_type = exact_type->is_aryptr(); + auto other_ary_type = other_type->is_aryptr(); + if (both_are_exact) { + if (exact_ary_type->is_flat() != other_ary_type->is_flat() || exact_ary_type->is_not_flat() != other_ary_type->is_not_flat() || + exact_ary_type->is_not_null_free() != other_ary_type->is_not_null_free() || exact_ary_type->is_atomic() != other_ary_type->is_atomic()) { + return true; + } + } else { + if (!exact_ary_type->is_atomic() && other_ary_type->is_atomic()) { + return true; + } + } + + auto exact_elem = exact_ary_type->elem(); + auto other_elem = other_ary_type->elem(); + assert(exact_elem->base() != Type::Bottom, "cannot have an exact bot[]"); + assert(!both_are_exact || other_elem->base() != Type::Bottom, "cannot have an exact bot[]"); + if (other_elem->base() == Type::Bottom) { + return false; + } + + if (exact_elem->make_ptr() != nullptr && other_elem->make_ptr() != nullptr) { + exact_type = exact_elem->make_ptr()->is_oopptr(); + other_type = other_elem->make_ptr()->is_oopptr(); + continue; + } + + if (exact_elem->base() != other_elem->base()) { + return true; + } else if (exact_elem->base() == Type::Int) { + return exact_ary_type->klass() != other_ary_type->klass(); + } else { + return false; + } + } + } +}; + +class TypeJavaPtrJoinHelper { +public: + template + static const typename PtrType::PtrType* javaptr_type_xjoin(const PtrType* t1, const PtrType* t2) { + if (t1 == t2) { + return t1; + } + + TypePtr::PTR ptr1 = t1->ptr(); + TypePtr::PTR ptr2 = t2->ptr(); + assert(ptr1 == TypePtr::Constant || ptr1 == TypePtr::NotNull || ptr1 == TypePtr::BotPTR, "unexpected ptr: %d", int(ptr1)); + assert(ptr2 == TypePtr::Constant || ptr2 == TypePtr::NotNull || ptr2 == TypePtr::BotPTR, "unexpected ptr: %d", int(ptr2)); + + if constexpr (PtrType::is_oopptr_type) { + return oopptr_type_xjoin(t1, t2); + } else { + return klassptr_type_xjoin(t1, t2); + } + } + +private: + template + static const typename OopType::PtrType* oopptr_type_xjoin(const OopType* t1, const OopType* t2) { + assert(t1 != t2, "must have been handled"); + Type::TYPES base1 = t1->base(); + Type::TYPES base2 = t2->base(); + assert(base1 == Type::InstPtr || base1 == Type::AryPtr, "must be an oopptr: %d", int(base1)); + assert(base2 == Type::InstPtr || base2 == Type::AryPtr, "must be an oopptr: %d", int(base2)); + + Type::Offset offset = join_offset(t1, t2); + auto interfaces = join_interfaces(t1, t2); + auto flat_in_array = join_flat_in_array(t1, t2); + int instance_id = join_instance_id(t1, t2); + auto speculative = join_speculative(t1, t2); + int inline_depth = join_inline_depth(t1, t2); + if (offset == Type::Offset::top) { + return OopType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset, speculative, inline_depth); + } else if ((t1->ptr() == TypePtr::Constant || t2->ptr() == TypePtr::Constant) && instance_id != TypeOopPtr::InstanceBot) { + // A constant oop cannot be produced by an allocation in the current compilation + return OopType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset, speculative, inline_depth); + } else if (flat_in_array == TypePtr::TopFlat || instance_id == TypeOopPtr::InstanceTop) { + TypePtr::PTR ptr = join_ptr_with_null(join_ptr(t1, t2)); + return OopType::PtrType::make(Type::AnyPtr, ptr, offset, speculative, inline_depth); + } + + if (base1 != base2) { + const typename OopType::InstType* inst_type; + const typename OopType::AryType* ary_type; + if (base1 == Type::InstPtr) { + inst_type = t1->is_instptr(); + ary_type = t2->is_aryptr(); + } else { + inst_type = t2->is_instptr(); + ary_type = t1->is_aryptr(); + } + + TypePtr::PTR ptr = join_ptr(t1, t2); + bool inst_type_can_contain_arrays = inst_type->instance_klass()->is_java_lang_Object() && !inst_type->klass_is_exact() && + OopType::AryType::_array_interfaces->contains(inst_type->interfaces()); + if (inst_type_can_contain_arrays) { + return OopType::AryType::make(ptr, ary_type->const_oop(), ary_type->ary(), ary_type->klass(), ary_type->klass_is_exact(), offset, ary_type->field_offset(), + instance_id, speculative, inline_depth, ary_type->is_autobox_cache()); + } else { + return OopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } else if (base1 == Type::InstPtr) { + return instptr_type_xjoin(t1->is_instptr(), t2->is_instptr(), offset, interfaces, flat_in_array, instance_id, speculative, inline_depth); + } else { + return aryptr_type_xjoin(t1->is_aryptr(), t2->is_aryptr(), offset, instance_id, speculative, inline_depth); + } + } + + template + static const typename InstOopType::PtrType* instptr_type_xjoin(const InstOopType* t1, const InstOopType* t2, Type::Offset offset, InterfacesType interfaces, + TypePtr::FlatInArray flat_in_array, int instance_id, const PtrType* speculative, int inline_depth) { + // Join 2 constants + if (t1->const_oop() != nullptr && t2->const_oop() != nullptr) { + if (t1->const_oop() != t2->const_oop()) { + return InstOopType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset, speculative, inline_depth); + } else { + return InstOopType::make(TypePtr::Constant, t1->instance_klass(), interfaces, true, t1->const_oop(), offset, flat_in_array, instance_id, speculative, inline_depth); + } + } + + // From here, at least one of the operand is not constant + TypePtr::PTR ptr = join_ptr(t1, t2); + auto const_oop = t1->const_oop() != nullptr ? t1->const_oop() : t2->const_oop(); + auto klass1 = t1->instance_klass(); + auto klass2 = t2->instance_klass(); + bool xk1 = t1->klass_is_exact(); + bool xk2 = t2->klass_is_exact(); + + if (xk1 && xk2) { + if (t1->instance_klass() == t2->instance_klass()) { + return InstOopType::make(ptr, klass1, interfaces, true, const_oop, offset, flat_in_array, instance_id, speculative, inline_depth); + } else { + return InstOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } else if (xk1) { + assert(klass1->is_loaded(), "pointer to an oop of an exact type must be loaded"); + if (non_exact_type_contains_exact_type(t2, t1, interfaces)) { + return InstOopType::make(ptr, klass1, interfaces, true, const_oop, offset, flat_in_array, instance_id, speculative, inline_depth); + } else { + return InstOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } else if (xk2) { + assert(klass2->is_loaded(), "pointer to an oop of an exact type must be loaded"); + if (non_exact_type_contains_exact_type(t1, t2, interfaces)) { + return InstOopType::make(ptr, klass2, interfaces, true, const_oop, offset, flat_in_array, instance_id, speculative, inline_depth); + } else { + return InstOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } + + assert(const_oop == nullptr && ptr != TypePtr::Constant, "const oop should have exact klass"); + if (!klass1->is_loaded() || !klass2->is_loaded()) { + // Consider an unloaded class to be a direct child of j.l.O and not have any subclass + if (klass1->is_java_lang_Object()) { + return InstOopType::make(ptr, klass2, interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, inline_depth); + } else if (klass2->is_java_lang_Object()) { + return InstOopType::make(ptr, klass1, interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, inline_depth); + } else if (klass1 == klass2) { + return InstOopType::make(ptr, klass1, interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, inline_depth); + } else { + return InstOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } + + // There is no opposite of LCA, there exists a non-null object o subtyping both A and B iff A + // is a subtype of B or B is a subtype of A + if (klass1->is_subtype_of(klass2)) { + return InstOopType::make(ptr, klass1, interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, inline_depth); + } else if (klass2->is_subtype_of(klass1)) { + return InstOopType::make(ptr, klass2, interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, inline_depth); + } else { + return InstOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + } + + template + static const typename AryOopType::PtrType* aryptr_type_xjoin(const AryOopType* t1, const AryOopType* t2, Type::Offset offset, int instance_id, + const PtrType* speculative, int inline_depth) { + using AryType = std::remove_pointer_tary())>; + using ElemType = decltype(t1->elem()); + using KlassType = decltype(t1->klass()); + + // Join of 2 different constants + if (t1->const_oop() != nullptr && t2->const_oop() != nullptr && t1->const_oop() != t2->const_oop()) { + return AryOopType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset, speculative, inline_depth); + } + + TypePtr::PTR ptr = join_ptr(t1, t2); + ElemType elem; + KlassType klass = nullptr; + join_ary_elem(elem, klass, t1, t2); + if (elem->empty()) { + return AryOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + + if (TypeJavaPtrMeetHelper::aryptr_klass_disjoint(t1, t2)) { + return AryOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + + auto size = t1->size()->join(t2->size())->isa_int(); + if (size == nullptr) { + return AryOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + + auto const_oop = t1->const_oop() != nullptr ? t1->const_oop() : t2->const_oop(); + bool stable = t1->is_stable() || t2->is_stable(); + bool flat = t1->is_flat() || t2->is_flat(); + bool not_flat = t1->is_not_flat() || t2->is_not_flat(); + bool null_free = t1->is_null_free() || t2->is_null_free(); + bool not_null_free = t1->is_not_null_free() || t2->is_not_null_free(); + bool atomic = t1->is_atomic() || t2->is_atomic(); + auto field_offset = t1->field_offset().join(t2->field_offset()); + if ((flat && not_flat) || (null_free && not_null_free) || field_offset == Type::Offset::top) { + return AryOopType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset, speculative, inline_depth); + } + + auto ary = AryType::make(elem, size, stable, flat, not_flat, null_free, not_null_free, atomic); + bool xk = t1->klass_is_exact() || t2->klass_is_exact(); + bool autobox_cache = t1->is_autobox_cache() || t2->is_autobox_cache(); + return AryOopType::make(ptr, const_oop, ary, klass, xk, offset, field_offset, instance_id, speculative, inline_depth, autobox_cache); + } + + template + static const typename KlassType::PtrType* klassptr_type_xjoin(const KlassType* t1, const KlassType* t2) { + assert(t1 != t2, "must have been handled"); + Type::TYPES base1 = t1->base(); + Type::TYPES base2 = t2->base(); + assert(base1 == Type::InstKlassPtr || base1 == Type::AryKlassPtr, "must be a klassptr: %d", int(base1)); + assert(base2 == Type::InstKlassPtr || base2 == Type::AryKlassPtr, "must be a klassptr: %d", int(base2)); + + Type::Offset offset = join_offset(t1, t2); + auto interfaces = join_interfaces(t1, t2); + auto flat_in_array = join_flat_in_array(t1, t2); + if (offset == Type::Offset::top) { + return KlassType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset); + } else if (flat_in_array == TypePtr::TopFlat) { + TypePtr::PTR ptr = join_ptr_with_null(join_ptr(t1, t2)); + return KlassType::PtrType::make(Type::AnyPtr, ptr, offset); + } + + if (base1 != base2) { + const typename KlassType::InstType* inst_type; + const typename KlassType::AryType* ary_type; + if (base1 == Type::InstKlassPtr) { + inst_type = t1->is_instklassptr(); + ary_type = t2->is_aryklassptr(); + } else { + inst_type = t2->is_instklassptr(); + ary_type = t1->is_aryklassptr(); + } + + TypePtr::PTR ptr = join_ptr(t1, t2); + bool inst_type_can_contain_arrays = inst_type->instance_klass()->is_java_lang_Object() && !inst_type->klass_is_exact() && + KlassType::AryType::_array_interfaces->contains(inst_type->interfaces()); + if (inst_type_can_contain_arrays) { + return KlassType::AryType::make(ptr, ary_type->elem(), ary_type->klass(), offset, ary_type->is_not_flat(), ary_type->is_not_null_free(), + ary_type->is_flat(), ary_type->is_null_free(), ary_type->is_atomic(), ary_type->is_refined_type()); + } else { + return KlassType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset); + } + } else if (base1 == Type::InstKlassPtr) { + return instklassptr_type_xjoin(t1->is_instklassptr(), t2->is_instklassptr(), offset, interfaces, flat_in_array); + } else { + return aryklassptr_type_xjoin(t1->is_aryklassptr(), t2->is_aryklassptr(), offset); + } + } + + template + static const typename InstKlassType::PtrType* instklassptr_type_xjoin(const InstKlassType* t1, const InstKlassType* t2, Type::Offset offset, + InterfacesType interfaces, TypePtr::FlatInArray flat_in_array) { + auto klass1 = t1->instance_klass(); + auto klass2 = t2->instance_klass(); + // Beware, when the exact klass pointer is an interface, instance_klass() is j.l.O and + // interfaces() is not empty + if (t1->ptr() == TypePtr::Constant && t2->ptr() == TypePtr::Constant) { + if (klass1 == klass2 && t1->interfaces() == t2->interfaces()) { + return InstKlassType::make(TypePtr::Constant, klass1, interfaces, offset, flat_in_array); + } else { + return InstKlassType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset); + } + } else if (t1->ptr() == TypePtr::Constant) { + if (non_exact_type_contains_exact_type(t2, t1, interfaces)) { + return InstKlassType::make(TypePtr::Constant, klass1, interfaces, offset, flat_in_array); + } else { + return InstKlassType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset); + } + } else if (t2->ptr() == TypePtr::Constant) { + if (non_exact_type_contains_exact_type(t1, t2, interfaces)) { + return InstKlassType::make(TypePtr::Constant, klass2, interfaces, offset, flat_in_array); + } else { + return InstKlassType::PtrType::make(Type::AnyPtr, TypePtr::TopPTR, offset); + } + } else { + TypePtr::PTR ptr = join_ptr(t1, t2); + if (klass1->is_subtype_of(klass2)) { + return InstKlassType::make(ptr, klass1, interfaces, offset, flat_in_array); + } else if (klass2->is_subtype_of(klass1)) { + return InstKlassType::make(ptr, klass2, interfaces, offset, flat_in_array); + } else { + return InstKlassType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset); + } + } + } + + template + static const typename AryKlassType::PtrType* aryklassptr_type_xjoin(const AryKlassType* t1, const AryKlassType* t2, Type::Offset offset) { + using ElemType = decltype(t1->elem()); + using KlassType = decltype(t1->klass()); + + TypePtr::PTR ptr = join_ptr(t1, t2); + ElemType elem; + KlassType klass = nullptr; + join_ary_elem(elem, klass, t1, t2); + bool not_flat = t1->is_not_flat() || t2->is_not_flat(); + bool not_null_free = t1->is_not_null_free() || t2->is_not_null_free(); + bool flat = t1->is_flat() || t2->is_flat(); + bool null_free = t1->is_null_free() || t2->is_null_free(); + if (elem->empty() || (flat && not_flat) || (null_free && not_null_free)) { + return AryKlassType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset); + } + + bool atomic = t1->is_atomic() || t2->is_atomic(); + bool refined = t1->is_refined_type() || t2->is_refined_type(); + if (t1->klass_is_exact() && (not_flat != t1->is_not_flat() || not_null_free != t1->is_not_null_free() || flat != t1->is_flat() || + null_free != t1->is_null_free() || atomic != t1->is_atomic() || refined != t1->is_refined_type())) { + return AryKlassType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset); + } + if (t2->klass_is_exact() && (not_flat != t2->is_not_flat() || not_null_free != t2->is_not_null_free() || flat != t2->is_flat() || + null_free != t2->is_null_free() || atomic != t2->is_atomic() || refined != t2->is_refined_type())) { + return AryKlassType::PtrType::make(Type::AnyPtr, join_ptr_with_null(ptr), offset); + } + + return AryKlassType::make(ptr, elem, klass, offset, not_flat, not_null_free, flat, null_free, atomic, refined); + } + + template + static TypePtr::PTR join_ptr(const PtrType* t1, const PtrType* t2) { + TypePtr::PTR ptr1 = t1->ptr(); + TypePtr::PTR ptr2 = t2->ptr(); + if (ptr1 == TypePtr::Constant || ptr2 == TypePtr::Constant) { + return TypePtr::Constant; + } else if (ptr1 == TypePtr::NotNull || ptr2 == TypePtr::NotNull) { + return TypePtr::NotNull; + } else { + return TypePtr::BotPTR; + } + } + + // When 2 TypePtrs seem unrelated, they may still join at null if both of them are + // TypePtr::BotPTR. + static TypePtr::PTR join_ptr_with_null(TypePtr::PTR ptr) { + return ptr == TypePtr::BotPTR ? TypePtr::Null : TypePtr::TopPTR; + } + + template + static Type::Offset join_offset(const PtrType* t1, const PtrType* t2) { + return Type::Offset(t1->offset()).join(Type::Offset(t2->offset())); + } + + template > + static InterfacesType join_interfaces(const PtrType* t1, const PtrType* t2) { + return t1->interfaces()->union_with(t2->interfaces()); + } + + template + static int join_instance_id(const OopType* t1, const OopType* t2) { + int id1 = t1->instance_id(); + int id2 = t2->instance_id(); + assert(id1 != TypeOopPtr::InstanceTop && id2 != TypeOopPtr::InstanceTop, "InstanceTop must be normalized to TypePtr::TopPTR"); + if (id1 == TypeOopPtr::InstanceBot) { + return id2; + } else if (id2 == TypeOopPtr::InstanceBot) { + return id1; + } else if (id1 == id2) { + return id1; + } else { + return TypeOopPtr::InstanceTop; + } + } + + template + static auto join_speculative(const OopType* t1, const OopType* t2) { + auto s1 = t1->speculative(); + auto s2 = t2->speculative(); + if (s1 == nullptr && s2 == nullptr) { + return s1; + } + + if (s1 == nullptr) { + s1 = t1; + } else if (s2 == nullptr) { + s2 = t2; + } + return s1->join(s2)->is_ptr(); + } + + template + static int join_inline_depth(const OopType* t1, const OopType* t2) { + return MIN2(t1->inline_depth(), t2->inline_depth()); + } + + template + static TypePtr::FlatInArray join_flat_in_array(const PtrType* t1, const PtrType* t2) { + auto v1 = t1->flat_in_array(); + auto v2 = t2->flat_in_array(); + assert(v1 != TypePtr::TopFlat && v2 != TypePtr::TopFlat, "TopFlat must be normalized to TopPTR"); + if (v1 == TypePtr::MaybeFlat) { + return v2; + } else if (v2 == TypePtr::MaybeFlat) { + return v1; + } else if (v1 == v2) { + return v1; + } else { + return TypePtr::TopFlat; + } + } + + template + static void join_ary_elem(const ElemType*& elem, CIKlassType& klass, const AryType* t1, const AryType* t2) { + const ElemType* elem1 = t1->elem(); + const ElemType* elem2 = t2->elem(); + if (elem1 == ElemType::BOTTOM) { + elem = elem2; + klass = t2->klass(); + return; + } else if (elem2 == ElemType::BOTTOM) { + elem = elem1; + klass = t1->klass(); + return; + } + + if (elem1->make_ptr() != nullptr && elem2->make_ptr() != nullptr) { + elem = elem1->join_speculative(elem2); + if (!elem->empty() && elem->make_ptr()->ptr() == TypePtr::Null) { + elem = ElemType::TOP; + } + return; + } + + if (elem1->base() != elem2->base()) { + elem = ElemType::TOP; + } else if (elem1->base() == Type::Int) { + // boolean[], byte[], short[], char[], int[] all use some kinds of TypeInt as their element + // type, klass is used to distinguish between them. As a result, different kinds of array + // should result in top. + if (t1->klass() != t2->klass()) { + elem = ElemType::TOP; + } else { + elem = elem1->join(elem2); + klass = t1->klass(); + } + } else { + elem = elem1->join(elem2); + } + } + + template + static bool non_exact_type_contains_exact_type(const InstType* non_exact_type, const InstType* exact_type, InterfacesType interfaces) { + assert(!non_exact_type->klass_is_exact() && exact_type->klass_is_exact(), "invalid arguments"); + auto non_exact_klass = non_exact_type->instance_klass(); + auto exact_klass = exact_type->instance_klass(); + // Supertypes of a loaded class should also be loaded + return (exact_klass->is_java_lang_Object() && non_exact_klass->is_java_lang_Object() && exact_type->interfaces() == interfaces) || + (non_exact_klass->is_loaded() && exact_klass->is_subtype_of(non_exact_klass) && interfaces->eq(exact_klass)); + } +}; + +#endif // SHARE_OPTO_TYPEJAVAPTR_HPP diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 1198713619dd..5e6a7c04a0bd 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -738,7 +738,7 @@ inline bool is_java_type(BasicType t) { return T_BOOLEAN <= t && t <= T_VOID; } -inline bool is_java_primitive(BasicType t) { +constexpr inline bool is_java_primitive(BasicType t) { return T_BOOLEAN <= t && t <= T_LONG; } diff --git a/test/hotspot/gtest/opto/test_typejavaptr.cpp b/test/hotspot/gtest/opto/test_typejavaptr.cpp new file mode 100644 index 000000000000..89fbebcf1e41 --- /dev/null +++ b/test/hotspot/gtest/opto/test_typejavaptr.cpp @@ -0,0 +1,2003 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "nmt/memTag.hpp" +#include "opto/type.hpp" +#include "opto/typejavaptr.hpp" +#include "unittest.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/ostream.hpp" +#include +#include + +class ciInstanceKlassMirror; +class ciArrayKlassMirror; +class TypeOopPtrMirror; +class TypeInstPtrMirror; +class TypeAryPtrMirror; +class TypeKlassPtrMirror; +class TypeInstKlassPtrMirror; +class TypeAryKlassPtrMirror; + +// This file contains unit tests for the implementation of TypeJavaPtrMeetHelper and +// TypeJavaPtrJoinHelper. We use mirror instances that mimic the behaviour of the real objects. +// There are several advantages in using them: +// - It is really hard to create a Type instance, while we can create mirror instances at will. +// - Type::make can be used to create an arbitrary instance, while we can limit the corresponding +// factories to only return some expected instances. This greatly increases the rigor of the +// tests. +// - Mirror instances are created at compile time, ensuring the absence of unexpected behaviors. + +class InterfaceSet { +public: + bool _i0; + bool _i1; + + constexpr InterfaceSet(bool i0, bool i1) : _i0(i0), _i1(i1) {} + + InterfaceSet intersection_with(InterfaceSet other) const { + return InterfaceSet(_i0 && other._i0, _i1 && other._i1); + } + + InterfaceSet union_with(InterfaceSet other) const { + return InterfaceSet(_i0 || other._i0, _i1 || other._i1); + } + + const InterfaceSet* operator->() const { + return this; + } + + constexpr bool operator==(InterfaceSet o) const { + return _i0 == o._i0 && _i1 == o._i1; + } + + constexpr bool operator!=(InterfaceSet o) const { + return !(*this == o); + } + + bool contains(InterfaceSet sub) const { + return (_i0 || !sub._i0) && (_i1 || !sub._i1); + } + + bool eq(const ciInstanceKlassMirror* ci_klass) const; + + void dump_on(outputStream& st) const { + if (_i0) { + st.print("x"); + } else { + st.print("_"); + } + if (_i1) { + st.print("x"); + } else { + st.print("_"); + } + } +}; + +class ciKlassMirror { +private: + // The instance_id of the allocation corresponding to this type, each type has 3 dedicated id, + // this value is the start of the 3 + int _instance_id; + +protected: + constexpr ciKlassMirror(int instance_id) : _instance_id(instance_id) {} + +public: + static constexpr bool verify_instance_id(); + + constexpr int instance_id() const { return _instance_id; } + + virtual bool is_inst() const = 0; + virtual bool is_ary() const = 0; + const ciInstanceKlassMirror* as_inst() const; + const ciArrayKlassMirror* as_ary() const; + + virtual void dump_on(outputStream& st) const = 0; +}; + +class ciInstanceKlassMirror : public ciKlassMirror { +private: + friend class ciEnvMirror; + + static constexpr size_t _samples_size = 8; + int _parent_idx; + InterfaceSet _interfaces; + bool _is_loaded; + bool _is_interface; + const char* _name; + + constexpr ciInstanceKlassMirror(int parent_idx, InterfaceSet interfaces, bool is_loaded, bool is_interface, const char* name, int instance_id) + : ciKlassMirror(instance_id), _parent_idx(parent_idx), _interfaces(interfaces), _is_loaded(is_loaded), _is_interface(is_interface), _name(name) {} + +public: + static const std::array _samples; + + constexpr InterfaceSet interfaces() const { return _interfaces; } + constexpr const ciInstanceKlassMirror* as_instance_klass() const { return this; } + constexpr bool is_loaded() const { return _is_loaded; } + constexpr bool is_interface() const { return _is_interface; } + constexpr bool is_java_lang_Object() const { return _parent_idx == -1; } + + constexpr const ciInstanceKlassMirror* parent() const { + if (is_java_lang_Object()) { + return nullptr; + } else { + return &_samples[_parent_idx]; + } + } + + constexpr bool is_subtype_of(const ciInstanceKlassMirror* other) const { + for (auto t = this; t != nullptr; t = t->parent()) { + if (t == other) { + return true; + } + } + return false; + } + + constexpr const ciInstanceKlassMirror* least_common_ancestor(const ciInstanceKlassMirror* other) const { + for (auto t = this; t != nullptr; t = t->parent()) { + if (other->is_subtype_of(t)) { + return t; + } + } + ShouldNotReachHere(); + } + + virtual bool is_inst() const override { return true; } + virtual bool is_ary() const override { return false; } + + virtual void dump_on(outputStream& st) const override { + st.print("%s", _name); + } +}; + +constexpr std::array ciInstanceKlassMirror::_samples{ + ciInstanceKlassMirror(-1, InterfaceSet(false, false), true, false, "Object", 1), // j.l.Object + ciInstanceKlassMirror(0, InterfaceSet(false, false), false, false, "unloaded", 4), // unloaded + ciInstanceKlassMirror(0, InterfaceSet(true, false), true, false, "A", 7), // A extends Object implements I0 + ciInstanceKlassMirror(2, InterfaceSet(true, true), true, false, "B", 10), // B extends A implements I1 + ciInstanceKlassMirror(2, InterfaceSet(true, false), true, false, "C", 13), // C extends A + ciInstanceKlassMirror(0, InterfaceSet(false, true), true, false, "D", 16), // D extends Object implements I1 + ciInstanceKlassMirror(0, InterfaceSet(true, false), true, true, "I0", 19), // I0 + ciInstanceKlassMirror(0, InterfaceSet(false, true), true, true, "I1", 22), // I1 +}; + +bool InterfaceSet::eq(const ciInstanceKlassMirror* ci_klass) const { + return ci_klass->interfaces() == *this; +} + +class ciArrayKlassMirror : public ciKlassMirror { +private: + static constexpr size_t _samples_size = (ciInstanceKlassMirror::_samples.size() + 3) * 2; + BasicType _bt; + bool _elem_is_array; + int _elem_idx; + + constexpr ciArrayKlassMirror(BasicType bt, bool elem_is_array, int elem_idx, int instance_id) + : ciKlassMirror(instance_id), _bt(bt), _elem_is_array(elem_is_array), _elem_idx(elem_idx) {} + +public: + static const std::array _samples; + + static constexpr const ciArrayKlassMirror& find(BasicType bt, const ciKlassMirror* elem) { + for (auto& sample : _samples) { + if (sample._bt == bt && sample.elem() == elem) { + return sample; + } + } + + ShouldNotReachHere(); + } + + constexpr BasicType elem_basic_type() const { return _bt; } + + constexpr const ciKlassMirror* elem() const { + if (_elem_idx == -1) { + return nullptr; + } else if (_elem_is_array) { + return &_samples[_elem_idx]; + } else { + return &ciInstanceKlassMirror::_samples[_elem_idx]; + } + } + + virtual bool is_inst() const override { return false; } + virtual bool is_ary() const override { return true; } + + virtual void dump_on(outputStream& st) const override { + if (_bt != T_OBJECT) { + st.print("%s[]", type2name(_bt)); + } else { + elem()->dump_on(st); + st.print("[]"); + } + } +}; + +// byte[] and int[] shares the same element base when they are expressed as a TypeAryPtr, while +// they have a different base from float[], so these 3 are used as representatives of primitive +// arrays +constexpr std::array ciArrayKlassMirror::_samples = { + ciArrayKlassMirror(T_BYTE, false, -1, 25), + ciArrayKlassMirror(T_INT, false, -1, 28), + ciArrayKlassMirror(T_FLOAT, false, -1, 31), + ciArrayKlassMirror(T_OBJECT, false, 0, 34), + ciArrayKlassMirror(T_OBJECT, false, 1, 37), + ciArrayKlassMirror(T_OBJECT, false, 2, 40), + ciArrayKlassMirror(T_OBJECT, false, 3, 43), + ciArrayKlassMirror(T_OBJECT, false, 4, 46), + ciArrayKlassMirror(T_OBJECT, false, 5, 49), + ciArrayKlassMirror(T_OBJECT, false, 6, 52), + ciArrayKlassMirror(T_OBJECT, false, 7, 55), + ciArrayKlassMirror(T_OBJECT, true, 0, 58), + ciArrayKlassMirror(T_OBJECT, true, 1, 61), + ciArrayKlassMirror(T_OBJECT, true, 2, 64), + ciArrayKlassMirror(T_OBJECT, true, 3, 67), + ciArrayKlassMirror(T_OBJECT, true, 4, 70), + ciArrayKlassMirror(T_OBJECT, true, 5, 73), + ciArrayKlassMirror(T_OBJECT, true, 6, 76), + ciArrayKlassMirror(T_OBJECT, true, 7, 79), + ciArrayKlassMirror(T_OBJECT, true, 8, 82), + ciArrayKlassMirror(T_OBJECT, true, 9, 85), + ciArrayKlassMirror(T_OBJECT, true, 10, 88), +}; + +const ciInstanceKlassMirror* ciKlassMirror::as_inst() const { + assert(is_inst(), "not an instance"); + return static_cast(this); +} + +const ciArrayKlassMirror* ciKlassMirror::as_ary() const { + assert(is_ary(), "not an array"); + return static_cast(this); +} + +constexpr bool ciKlassMirror::verify_instance_id() { + int expected = 1; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.instance_id() != expected) { + return false; + } + expected += 3; + } + for (auto& ci_klass : ciArrayKlassMirror::_samples) { + if (ci_klass.instance_id() != expected) { + return false; + } + expected += 3; + } + + return true; +} + +static_assert(ciKlassMirror::verify_instance_id()); + +class ciEnvMirror { +private: + static const ciEnvMirror _instance; + +public: + static constexpr const ciEnvMirror* current() { return &_instance; } + constexpr const ciInstanceKlassMirror* Object_klass() const { return &ciInstanceKlassMirror::_samples[0]; } +}; +constexpr ciEnvMirror ciEnvMirror::_instance; + +class InstanceMirror { +private: + const ciKlassMirror* _klass; + int _idx; + +public: + constexpr InstanceMirror(const ciKlassMirror& klass, int idx) : _klass(&klass), _idx(idx) {} + constexpr InstanceMirror(std::nullptr_t) : _klass(nullptr), _idx(0) {} + + constexpr int idx() const { return _idx; } + constexpr const ciKlassMirror* klass() const { return _klass; } + + constexpr int array_length() const { + // A little sneaky, static_cast to the incorrect type will be rejected in a constexpr + // evaluation. May change to _klass->is_ary() when C++20 is available. + assert(_klass != nullptr && static_cast(_klass) != nullptr, "must be an array"); + switch (_idx) { + case 0: + case 1: + return 1; + case 2: + return 2; + case 3: + return 0; + case 4: + case 5: + return 3; + default: + ShouldNotReachHere(); + } + } + + constexpr bool operator==(const InstanceMirror& o) const { + return _klass == o._klass && _idx == o._idx; + } + + constexpr bool operator!=(const InstanceMirror& o) const { + return !(*this == o); + } + + constexpr bool operator!=(std::nullptr_t) const { + return _klass != nullptr; + } +}; + +template +class AryElemType { +private: + static constexpr size_t _1d_samples_size = ciInstanceKlassMirror::_samples.size() + 5; + + BasicType _bt; + const PtrType* _ptr_type; + +public: + static const AryElemType* const TOP; + static const AryElemType* const BOTTOM; + + constexpr AryElemType(BasicType bt, const PtrType* ptr_type) : _bt(bt), _ptr_type(ptr_type) { + assert((bt == T_OBJECT) == (ptr_type != nullptr), ""); + } + + constexpr AryElemType() : AryElemType(T_ILLEGAL, nullptr) {} + + static constexpr const AryElemType* find(BasicType bt, const PtrType* ptr_type) { + auto res = find_1d(bt, ptr_type); + if (res != nullptr) { + return res; + } + + res = find_2d(bt, ptr_type); + assert(res != nullptr, "must find an instance"); + return res; + } + + static constexpr const AryElemType* find_1d(BasicType bt, const PtrType* ptr_type); + static constexpr const AryElemType* find_2d(BasicType bt, const PtrType* ptr_type); + + constexpr BasicType basic_type() const { return _bt; } + constexpr bool empty() const { return _bt == T_ILLEGAL; } + constexpr const PtrType* make_ptr() const { return _ptr_type; } + + constexpr Type::TYPES base() const { + if (_bt == T_VOID) { + return Type::Bottom; + } else if (_bt == T_ILLEGAL) { + ShouldNotReachHere(); + } else if (_bt == T_BYTE || _bt == T_INT) { + return Type::Int; + } else if (_bt == T_FLOAT) { + return Type::FloatBot; + } else { + assert(_bt == T_OBJECT, "unexpected BasicType %s", type2name(_bt)); + assert(_ptr_type != nullptr, "must have element type info"); + return _ptr_type->base(); + } + } + + const AryElemType* meet(const AryElemType* other) const { return meet_speculative(other); } + const AryElemType* join(const AryElemType* other) const { return join_speculative(other); } + + const AryElemType* meet_speculative(const AryElemType* other) const { + if (_bt != other->_bt) { + return BOTTOM; + } else if (_bt != T_OBJECT) { + return this; + } + + return find(T_OBJECT, TypeJavaPtrMeetHelper::javaptr_type_xmeet(_ptr_type, other->_ptr_type)); + } + + const AryElemType* join_speculative(const AryElemType* other) const { + if (_bt != other->_bt) { + return TOP; + } else if (_bt != T_OBJECT) { + return this; + } + + auto ptr_type = TypeJavaPtrJoinHelper::javaptr_type_xjoin(_ptr_type, other->_ptr_type); + if (TypePtr::PTR ptr_ptr = ptr_type->ptr(); ptr_ptr == TypePtr::TopPTR || ptr_ptr == TypePtr::Null) { + return TOP; + } + + return find(T_OBJECT, static_cast(ptr_type)); + } +}; + +class TypePtrMirror { +private: + static constexpr size_t _samples_size = 8; + Type::TYPES _base; + TypePtr::PTR _ptr; + Type::Offset _offset; + + static const std::array _samples; + +protected: + constexpr TypePtrMirror(Type::TYPES base, TypePtr::PTR ptr, Type::Offset offset) : _base(base), _ptr(ptr), _offset(offset) {} + + void dump_ptr(outputStream& st) const { + if (ptr() == TypePtr::BotPTR) { + st.print("BotPTR"); + } else if (ptr() == TypePtr::NotNull) { + st.print("NotNull"); + } else if (ptr() == TypePtr::Constant) { + st.print("Constant"); + } else if (ptr() == TypePtr::Null) { + st.print("Null"); + } else { + assert(ptr() == TypePtr::TopPTR, "unexpected ptr %d", int(ptr())); + st.print("TopPTR"); + } + } + + void dump_offset(outputStream& st) const { + if (offset() == Type::OffsetBot) { + st.print("offset=bot"); + } else if (offset() == Type::OffsetTop) { + st.print("offset=top"); + } else { + st.print("offset=%d", offset()); + } + } + +public: + using ciEnv = ciEnvMirror; + using PtrType = TypePtrMirror; + + static const TypePtrMirror* make(Type::TYPES base, TypePtr::PTR ptr, Type::Offset offset, const TypePtrMirror* speculative = nullptr, int inline_depth = 0) { + assert(base == Type::AnyPtr, "unexpected base %d", int(base)); + assert(speculative == nullptr && inline_depth == 0, "unsupported"); + for (auto& sample : _samples) { + if (sample.ptr() == ptr && sample.offset() == offset.get()) { + return &sample; + } + } + + ShouldNotReachHere(); + } + + constexpr Type::TYPES base() const { return _base; } + constexpr TypePtr::PTR ptr() const { return _ptr; } + constexpr int offset() const { return _offset.get(); } + constexpr TypePtr::FlatInArray flat_in_array() const { return TypePtr::NotFlat; } + constexpr bool empty() const { return ptr() == TypePtr::TopPTR; } + + const TypePtrMirror* meet(const TypePtrMirror* o) const { ShouldNotReachHere(); } + const TypePtrMirror* join(const TypePtrMirror* o) const { ShouldNotReachHere(); } + const TypePtrMirror* is_ptr() const { ShouldNotReachHere(); } + + virtual const TypeOopPtrMirror* is_oopptr() const { ShouldNotReachHere(); } + virtual const TypeKlassPtrMirror* is_klassptr() const { ShouldNotReachHere(); } + + virtual void dump_on(outputStream& st) const { + st.print("AnyPtr:"); + dump_ptr(st); + st.print(" - "); + dump_offset(st); + } +}; + +constexpr std::array TypePtrMirror::_samples = { + TypePtrMirror(Type::AnyPtr, TypePtr::TopPTR, Type::Offset::bottom), + TypePtrMirror(Type::AnyPtr, TypePtr::TopPTR, Type::Offset(0)), + TypePtrMirror(Type::AnyPtr, TypePtr::TopPTR, Type::Offset(1)), + TypePtrMirror(Type::AnyPtr, TypePtr::TopPTR, Type::Offset::top), + TypePtrMirror(Type::AnyPtr, TypePtr::Null, Type::Offset::bottom), + TypePtrMirror(Type::AnyPtr, TypePtr::Null, Type::Offset(0)), + TypePtrMirror(Type::AnyPtr, TypePtr::Null, Type::Offset(1)), + TypePtrMirror(Type::AnyPtr, TypePtr::Null, Type::Offset::top), +}; + +class TypeOopPtrMirror : public TypePtrMirror { +private: + InterfaceSet _interfaces; + int _instance_id; + InstanceMirror _const_oop; + bool _klass_is_exact; + +protected: + constexpr TypeOopPtrMirror(Type::TYPES base, TypePtr::PTR ptr, InterfaceSet interfaces, InstanceMirror const_oop, bool klass_is_exact, Type::Offset offset, int instance_id) + : TypePtrMirror(base, ptr, offset), _interfaces(interfaces), _instance_id(instance_id), _const_oop(const_oop), _klass_is_exact(klass_is_exact) {} + + void dump_instance(outputStream& st) const { + st.print("const_oop="); + if (const_oop() == nullptr) { + st.print("null"); + } else { + st.print("%d", const_oop().idx()); + } + st.print(" - instance_id="); + if (instance_id() == TypeOopPtr::InstanceBot) { + st.print("bot"); + } else { + st.print("%d", instance_id()); + } + } + +public: + static constexpr bool is_oopptr_type = true; + using InstType = TypeInstPtrMirror; + using AryType = TypeAryPtrMirror; + + constexpr InterfaceSet interfaces() const { return _interfaces; } + constexpr InstanceMirror const_oop() const { return _const_oop; } + constexpr bool klass_is_exact() const { return _klass_is_exact; } + constexpr int instance_id() const { return _instance_id; } + constexpr const TypePtrMirror* speculative() const { return nullptr; } + constexpr int inline_depth() const { return 0; } + + virtual const TypeOopPtrMirror* is_oopptr() const override { return this; } + virtual const TypeInstPtrMirror* is_instptr() const = 0; + virtual const TypeAryPtrMirror* is_aryptr() const = 0; + + virtual void dump_on(outputStream& st) const override = 0; +}; + +static constexpr size_t TypeInstPtr_samples_size() { + size_t res = 0; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_interface()) { + continue; + } + + // The constant instance + res += ci_klass.is_loaded() ? 2 : 0; + + // The exact-klass instances, with different instance_id values + res += ci_klass.is_loaded() ? 4 : 0; + + // The non-exact-klass instances + if (ci_klass.interfaces()._i0 && ci_klass.interfaces()._i1) { + res += 2; + } else if (ci_klass.interfaces()._i0 || ci_klass.interfaces()._i1) { + res += 4; + } else { + res += 8; + } + } + + // Different offset values + return res * 3; +} + +class TypeInstPtrMirror : public TypeOopPtrMirror { +private: + const ciInstanceKlassMirror* _klass; + + constexpr TypeInstPtrMirror(TypePtr::PTR ptr, const ciInstanceKlassMirror& klass, InterfaceSet interfaces, bool klass_is_exact, + InstanceMirror const_oop, Type::Offset offset, int instance_id) + : TypeOopPtrMirror(Type::InstPtr, ptr, interfaces, const_oop, klass_is_exact, offset, instance_id), + _klass(&klass) { + assert(!klass.is_interface(), ""); + } + + static constexpr auto generate_samples(); + +public: + static const std::array _samples; + + constexpr TypeInstPtrMirror() + : TypeOopPtrMirror(Type::Bad, TypePtr::TopPTR, InterfaceSet(false, false), nullptr, false, Type::Offset(0), 0), + _klass(nullptr) {} + + static constexpr const TypeInstPtrMirror* make(TypePtr::PTR ptr, const ciInstanceKlassMirror* klass, InterfaceSet interfaces, bool klass_is_exact, + InstanceMirror const_oop = nullptr, Type::Offset offset = Type::Offset(0), TypePtr::FlatInArray flat_in_array = TypePtr::NotFlat, + int instance_id = TypeOopPtr::InstanceBot, const TypePtrMirror* speculative = nullptr, int inline_depth = 0) { + assert(flat_in_array == TypePtr::NotFlat && speculative == nullptr && inline_depth == 0, "unsupported"); + for (auto& sample : _samples) { + if (sample.ptr() == ptr && sample.instance_klass() == klass && sample.interfaces() == interfaces && sample.klass_is_exact() == klass_is_exact && + sample.const_oop() == const_oop && sample.offset() == offset.get() && sample.instance_id() == instance_id) { + return &sample; + } + } + + ShouldNotReachHere(); + } + + constexpr const ciInstanceKlassMirror* instance_klass() const { return _klass; } + + virtual const TypeInstPtrMirror* is_instptr() const override { return this; } + virtual const TypeAryPtrMirror* is_aryptr() const override { ShouldNotReachHere(); } + + virtual void dump_on(outputStream& st) const override { + st.print("InstPtr:"); + dump_ptr(st); + st.print(" - "); + instance_klass()->dump_on(st); + st.print("("); + interfaces().dump_on(st); + st.print(") - klass_is_exact=%d - ", klass_is_exact()); + dump_instance(st); + st.print(" - "); + dump_offset(st); + } +}; + +constexpr auto TypeInstPtrMirror::generate_samples() { + std::array res; + size_t sample_idx = 0; + auto fill_result = [&](TypePtr::PTR ptr, const ciInstanceKlassMirror& ci_klass, InterfaceSet interfaces, bool klass_is_exact, InstanceMirror const_oop, int instance_id) { + res[sample_idx] = TypeInstPtrMirror(ptr, ci_klass, interfaces, klass_is_exact, const_oop, Type::Offset::bottom, instance_id); + sample_idx++; + res[sample_idx] = TypeInstPtrMirror(ptr, ci_klass, interfaces, klass_is_exact, const_oop, Type::Offset(0), instance_id); + sample_idx++; + res[sample_idx] = TypeInstPtrMirror(ptr, ci_klass, interfaces, klass_is_exact, const_oop, Type::Offset(1), instance_id); + sample_idx++; + }; + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + if (ci_klass.is_loaded()) { + fill_result(TypePtr::Constant, ci_klass, interfaces, true, InstanceMirror(ci_klass, 0), TypeOopPtr::InstanceBot); + fill_result(TypePtr::Constant, ci_klass, interfaces, true, InstanceMirror(ci_klass, 1), TypeOopPtr::InstanceBot); + fill_result(TypePtr::BotPTR, ci_klass, interfaces, true, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, interfaces, true, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, interfaces, true, nullptr, ci_klass.instance_id()); + fill_result(TypePtr::NotNull, ci_klass, interfaces, true, nullptr, ci_klass.instance_id() + 1); + } + + fill_result(TypePtr::BotPTR, ci_klass, interfaces, false, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, interfaces, false, nullptr, TypeOopPtr::InstanceBot); + if (!interfaces._i0) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, interfaces._i1), false, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, interfaces._i1), false, nullptr, TypeOopPtr::InstanceBot); + } + if (!interfaces._i1) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(interfaces._i0, true), false, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(interfaces._i0, true), false, nullptr, TypeOopPtr::InstanceBot); + } + if (!interfaces._i0 && !interfaces._i1) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, true), false, nullptr, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, true), false, nullptr, TypeOopPtr::InstanceBot); + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeInstPtrMirror::_samples = generate_samples(); + +class ArySizeType { +private: + friend class TypeAryPtrMirror; + + bool _empty; + int _lo; + int _hi; + + constexpr ArySizeType(bool empty, int lo, int hi) : _empty(empty), _lo(lo), _hi(hi) { + assert((!empty && lo <= hi) || (empty && lo == 0 && hi == 0), "invariant"); + assert(lo >= 0 && hi <= 3, "constraint"); + } + +public: + static const ArySizeType BOTTOM; + + ArySizeType meet(ArySizeType other) const { + assert(!_empty && !other._empty, "must not have empty type here"); + return ArySizeType(false, MIN2(_lo, other._lo), MAX2(_hi, other._hi)); + } + + ArySizeType join(ArySizeType other) const { + assert(!_empty && !other._empty, "must not have empty type here"); + int lo = MAX2(_lo, other._lo); + int hi = MIN2(_hi, other._hi); + if (lo > hi) { + return ArySizeType(true, 0, 0); + } else { + return ArySizeType(false, lo, hi); + } + } + + const ArySizeType* operator->() const { return this; } + const ArySizeType& is_int() const { assert(!_empty, "must not be empty"); return *this; } + const ArySizeType& isa_int() const { return *this; } + + constexpr bool contains(int len) const { + assert(0 <= len && len <= 3, "unsupported"); + return _lo <= len && len <= _hi; + } + + constexpr bool operator==(const ArySizeType& other) const { + return _empty == other._empty && _lo == other._lo && _hi == other._hi; + } + + constexpr bool operator!=(const ArySizeType& other) const { + return !(*this == other); + } + + constexpr bool operator==(std::nullptr_t) const { + return _empty; + } + + constexpr bool operator!=(std::nullptr_t) const { + return !_empty; + } +}; + +constexpr ArySizeType ArySizeType::BOTTOM(false, 0, 3); + +class TypeAryMirror { +private: + friend class TypeAryPtrMirror; + + const AryElemType* _elem; + ArySizeType _size; + +public: + constexpr TypeAryMirror(const AryElemType* elem, ArySizeType size) : _elem(elem), _size(size) { + assert(size != nullptr, ""); + } + + static TypeAryMirror make(const AryElemType* elem, ArySizeType size, bool is_stable, bool flat, bool not_flat, bool null_free, bool not_null_free, bool atomic) { + assert(!is_stable && !flat && not_flat && !null_free && not_null_free && atomic, "unsupported"); + return TypeAryMirror(elem, size); + } +}; + +static constexpr size_t TypeAryPtr_1d_elem_samples_size() { + size_t res = 0; + // top, bot, byte, int, float + res += 5; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_interface()) { + continue; + } + + if (ci_klass.interfaces()._i0 && ci_klass.interfaces()._i1) { + res += 1; + } else if (ci_klass.interfaces()._i0 || ci_klass.interfaces()._i1) { + res += 2; + } else { + res += 4; + } + } + + return res; +} + +static constexpr size_t TypeAryPtr_1d_exact_samples_size() { + size_t res = 0; + // byte[], int[], float[] + res += 3; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_loaded()) { + res += 1; + } + } + + return res; +} + +static constexpr size_t TypeAryPtr_1d_nonexact_samples_size() { + size_t res = 0; + // bot[] + res += 1; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_interface()) { + continue; + } + + if (ci_klass.interfaces()._i0 && ci_klass.interfaces()._i1) { + res += 1; + } else if (ci_klass.interfaces()._i0 || ci_klass.interfaces()._i1) { + res += 2; + } else { + res += 4; + } + } + + return res; +} + +// All test instances have is_stable() == false, is_auto_box_cache() == false, is_flat() == false, +// is_not_flat() == true, is_null_free() == false, is_not_null_free() == true, is_atomic() == true, +// field_offset() == Offset::bottom. All other parameters are included exhaustively. +class TypeAryPtrMirror : public TypeOopPtrMirror { +private: + static constexpr size_t _1d_elem_samples_size = TypeAryPtr_1d_elem_samples_size(); + static constexpr size_t _1d_samples_size = (TypeAryPtr_1d_exact_samples_size() * 15 + TypeAryPtr_1d_nonexact_samples_size() * 10) * 3; + static constexpr size_t _2d_elem_samples_size = TypeAryPtr_1d_nonexact_samples_size() + 3; + static constexpr size_t _2d_samples_size = _1d_samples_size; + + TypeAryMirror _ary; + const ciArrayKlassMirror* _klass; + + constexpr TypeAryPtrMirror(TypePtr::PTR ptr, InstanceMirror const_oop, const TypeAryMirror& ary, + const ciArrayKlassMirror* klass, bool klass_is_exact, Type::Offset offset, int instance_id) + : TypeOopPtrMirror(TypePtr::AryPtr, ptr, _array_interfaces, const_oop, klass_is_exact, offset, instance_id), + _ary(ary), _klass(klass) { + assert(ary._elem != nullptr, ""); + } + + template + static constexpr void fill_samples_helper(R& res, size_t& sample_idx, TypePtr::PTR ptr, InstanceMirror const_oop, const AryElemType* elem, + const ciArrayKlassMirror* klass, bool klass_is_exact, int instance_id, Type::Offset offset); + + static constexpr auto generate_1d_elem_samples(); + static constexpr auto generate_1d_samples(); + static constexpr auto generate_2d_elem_samples(); + static constexpr auto generate_2d_samples(); + +public: + static constexpr InterfaceSet _array_interfaces = InterfaceSet(false, true); + static const std::array, _1d_elem_samples_size> _1d_elem_samples; + static const std::array _1d_samples; + static const std::array, _2d_elem_samples_size> _2d_elem_samples; + static const std::array _2d_samples; + + constexpr TypeAryPtrMirror() + : TypeOopPtrMirror(Type::Bad, TypePtr::TopPTR, _array_interfaces, nullptr, false, Type::Offset(0), 0), + _ary(nullptr, ArySizeType(false, 0, 0)), _klass(nullptr) {} + + static constexpr const TypeAryPtrMirror* make(TypePtr::PTR ptr, InstanceMirror const_oop, const TypeAryMirror& ary, const ciArrayKlassMirror* klass, bool klass_is_exact, + Type::Offset offset, Type::Offset field_offset, int instance_id, const TypePtrMirror* speculative = nullptr, int inline_depth = 0, bool is_autobox_cache = false) { + assert(field_offset == Type::Offset::bottom && speculative == nullptr && inline_depth == 0 && !is_autobox_cache, "unsupported"); + auto match = [&](const TypeAryPtrMirror& sample) { + return sample.ptr() == ptr && sample.const_oop() == const_oop && sample.elem() == ary._elem && sample.size() == ary._size && + sample.klass() == klass && sample.klass_is_exact() == klass_is_exact && sample.offset() == offset.get() && sample.instance_id() == instance_id; + }; + + for (auto& sample : _1d_samples) { + if (match(sample)) { + return &sample; + } + } + + for (auto& sample : _2d_samples) { + if (match(sample)) { + return &sample; + } + } + + ShouldNotReachHere(); + } + + constexpr const TypeAryMirror ary() const { return _ary; } + constexpr const AryElemType* elem() const { return _ary._elem; } + constexpr ArySizeType size() const { return _ary._size; } + constexpr bool is_stable() const { return false; } + constexpr const ciArrayKlassMirror* klass() const { return _klass; } + constexpr bool is_autobox_cache() const { return false; } + + bool is_flat() const { return false; } + bool is_not_flat() const { return true; } + bool is_null_free() const { return false; } + bool is_not_null_free() const { return true; } + bool is_atomic() const { return true; } + Type::Offset field_offset() const { return Type::Offset::bottom; } + + virtual const TypeInstPtrMirror* is_instptr() const override { ShouldNotReachHere(); } + virtual const TypeAryPtrMirror* is_aryptr() const override { return this; } + + virtual void dump_on(outputStream& st) const override { + st.print("AryPtr:"); + dump_ptr(st); + st.print(" - "); + if (elem()->base() == Type::Bottom) { + st.print("bot"); + } else if (elem()->basic_type() != T_OBJECT) { + st.print("%s", type2name(elem()->basic_type())); + } else { + st.print("("); + elem()->make_ptr()->dump_on(st); + st.print(")"); + } + st.print("[%d - %d] - klass_is_exact=%d - ", size()._lo, size()._hi, klass_is_exact()); + dump_instance(st); + st.print(" - "); + dump_offset(st); + } +}; + +template <> +constexpr const AryElemType* AryElemType::TOP = &TypeAryPtrMirror::_1d_elem_samples[0]; + +template <> +constexpr const AryElemType* AryElemType::BOTTOM = &TypeAryPtrMirror::_1d_elem_samples[1]; + +template <> +constexpr const AryElemType* AryElemType::find_1d(BasicType bt, const TypeOopPtrMirror* ptr_type) { + for (auto& sample : TypeAryPtrMirror::_1d_elem_samples) { + if (sample._bt == bt && sample._ptr_type == ptr_type) { + return &sample; + } + } + return nullptr; +} + +template <> +constexpr const AryElemType* AryElemType::find_2d(BasicType bt, const TypeOopPtrMirror* ptr_type) { + for (auto& sample : TypeAryPtrMirror::_2d_elem_samples) { + if (sample._bt == bt && sample._ptr_type == ptr_type) { + return &sample; + } + } + return nullptr; +} + +constexpr auto TypeAryPtrMirror::generate_1d_elem_samples() { + std::array, _1d_elem_samples_size> res; + res[0] = AryElemType(T_ILLEGAL, nullptr); + res[1] = AryElemType(T_VOID, nullptr); + res[2] = AryElemType(T_BYTE, nullptr); + res[3] = AryElemType(T_INT, nullptr); + res[4] = AryElemType(T_FLOAT, nullptr); + + size_t sample_idx = 5; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + res[sample_idx] = AryElemType(T_OBJECT, TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, interfaces, false)); + sample_idx++; + if (!interfaces._i0) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(true, interfaces._i1), false)); + sample_idx++; + } + if (!interfaces._i1) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(interfaces._i0, true), false)); + sample_idx++; + } + if (!interfaces._i0 && !interfaces._i1) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(true, true), false)); + sample_idx++; + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array, TypeAryPtrMirror::_1d_elem_samples_size> TypeAryPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); + +template +constexpr void TypeAryPtrMirror::fill_samples_helper(R& res, size_t& sample_idx, TypePtr::PTR ptr, InstanceMirror const_oop, const AryElemType* elem, + const ciArrayKlassMirror* klass, bool klass_is_exact, int instance_id, Type::Offset offset) { + if (const_oop != nullptr) { + TypeAryMirror ary(elem, ArySizeType(false, const_oop.array_length(), const_oop.array_length())); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + } else if (instance_id != TypeOopPtr::InstanceBot) { + // Each klass is reserved 3 distinct instance_id, so we try to infer whether which instance this + // is by finding its remainder modulo 3 + if (instance_id % 3 == 1) { + TypeAryMirror ary(elem, ArySizeType(false, 0, 1)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + ary = TypeAryMirror(elem, ArySizeType(false, 1, 1)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + } else { + TypeAryMirror ary(elem, ArySizeType(false, 2, 3)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + } + } else { + TypeAryMirror ary(elem, ArySizeType(false, 0, 1)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + ary = TypeAryMirror(elem, ArySizeType(false, 1, 1)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + + ary = TypeAryMirror(elem, ArySizeType(false, 0, 3)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + ary = TypeAryMirror(elem, ArySizeType(false, 1, 3)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + ary = TypeAryMirror(elem, ArySizeType(false, 2, 3)); + res[sample_idx] = TypeAryPtrMirror(ptr, const_oop, ary, klass, klass_is_exact, offset, instance_id); + sample_idx++; + } +} + +constexpr auto TypeAryPtrMirror::generate_1d_samples() { + std::array res; + size_t sample_idx = 0; + auto fill_result = [&](TypePtr::PTR ptr, InstanceMirror const_oop, const AryElemType* elem, + const ciArrayKlassMirror* klass, bool klass_is_exact, int instance_id) { + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset::bottom); + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset(0)); + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset(1)); + }; + + auto bot_ary_elem = AryElemType::find_1d(T_VOID, nullptr); + fill_result(TypePtr::BotPTR, nullptr, bot_ary_elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, bot_ary_elem, nullptr, false, TypeOopPtr::InstanceBot); + + auto byte_ary_elem = AryElemType::find_1d(T_BYTE, nullptr); + auto& byte_ary_klass = ciArrayKlassMirror::find(T_BYTE, nullptr); + fill_result(TypePtr::BotPTR, nullptr, byte_ary_elem, &byte_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, byte_ary_elem, &byte_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, byte_ary_elem, &byte_ary_klass, true, byte_ary_klass.instance_id()); + fill_result(TypePtr::NotNull, nullptr, byte_ary_elem, &byte_ary_klass, true, byte_ary_klass.instance_id() + 1); + fill_result(TypePtr::Constant, InstanceMirror(byte_ary_klass, 0), byte_ary_elem, &byte_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::Constant, InstanceMirror(byte_ary_klass, 1), byte_ary_elem, &byte_ary_klass, true, TypeOopPtr::InstanceBot); + + auto int_ary_elem = AryElemType::find_1d(T_INT, nullptr); + auto& int_ary_klass = ciArrayKlassMirror::find(T_INT, nullptr); + fill_result(TypePtr::BotPTR, nullptr, int_ary_elem, &int_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, int_ary_elem, &int_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, int_ary_elem, &int_ary_klass, true, int_ary_klass.instance_id()); + fill_result(TypePtr::NotNull, nullptr, int_ary_elem, &int_ary_klass, true, int_ary_klass.instance_id() + 1); + fill_result(TypePtr::Constant, InstanceMirror(int_ary_klass, 0), int_ary_elem, &int_ary_klass, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::Constant, InstanceMirror(int_ary_klass, 1), int_ary_elem, &int_ary_klass, true, TypeOopPtr::InstanceBot); + + auto float_ary_elem = AryElemType::find_1d(T_FLOAT, nullptr); + auto& float_ary_klass = ciArrayKlassMirror::find(T_FLOAT, nullptr); + fill_result(TypePtr::BotPTR, nullptr, float_ary_elem, nullptr, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, float_ary_elem, nullptr, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, float_ary_elem, nullptr, true, float_ary_klass.instance_id()); + fill_result(TypePtr::NotNull, nullptr, float_ary_elem, nullptr, true, float_ary_klass.instance_id() + 1); + fill_result(TypePtr::Constant, InstanceMirror(float_ary_klass, 0), float_ary_elem, nullptr, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::Constant, InstanceMirror(float_ary_klass, 1), float_ary_elem, nullptr, true, TypeOopPtr::InstanceBot); + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (ci_klass.is_loaded()) { + auto& ci_instance_klass = ci_klass.is_interface() ? *ciEnvMirror::current()->Object_klass() : ci_klass; + auto elem_ptr_type = TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_instance_klass, ci_klass.interfaces(), false); + auto elem = AryElemType::find_1d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, TypeOopPtr::InstanceBot); + + auto& ci_ary_klass = ciArrayKlassMirror::find(T_OBJECT, &ci_klass); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, ci_ary_klass.instance_id()); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, ci_ary_klass.instance_id() + 1); + + InstanceMirror const_oop_0(ci_ary_klass, 0); + fill_result(TypePtr::Constant, const_oop_0, elem, nullptr, true, TypeOopPtr::InstanceBot); + InstanceMirror const_oop_1(ci_ary_klass, 1); + fill_result(TypePtr::Constant, const_oop_1, elem, nullptr, true, TypeOopPtr::InstanceBot); + } + + if (ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + { + auto elem_ptr_type = TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, interfaces, false); + auto elem = AryElemType::find_1d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + } + + if (!interfaces._i0) { + auto elem_ptr_type = TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(true, interfaces._i1), false); + auto elem = AryElemType::find_1d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + } + + if (!interfaces._i1) { + auto elem_ptr_type = TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(interfaces._i0, true), false); + auto elem = AryElemType::find_1d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + } + + if (!interfaces._i0 && !interfaces._i1) { + auto elem_ptr_type = TypeInstPtrMirror::make(TypePtr::BotPTR, &ci_klass, InterfaceSet(true, true), false); + auto elem = AryElemType::find_1d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeAryPtrMirror::_1d_samples = generate_1d_samples(); + +constexpr auto TypeAryPtrMirror::generate_2d_elem_samples() { + std::array, _2d_elem_samples_size> res; + size_t sample_idx = 0; + + for (auto& elem_ptr_type : _1d_samples) { + if (elem_ptr_type.ptr() != TypePtr::BotPTR || elem_ptr_type.size() != ArySizeType::BOTTOM || elem_ptr_type.offset() != 0) { + continue; + } + + bool klass_is_exact = is_java_primitive(elem_ptr_type.elem()->basic_type()); + if (elem_ptr_type.klass_is_exact() != klass_is_exact) { + continue; + } + + res[sample_idx] = AryElemType(T_OBJECT, &elem_ptr_type); + sample_idx++; + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array, TypeAryPtrMirror::_2d_elem_samples_size> TypeAryPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); + +constexpr auto TypeAryPtrMirror::generate_2d_samples() { + std::array res; + size_t sample_idx = 0; + auto fill_result = [&](TypePtr::PTR ptr, InstanceMirror const_oop, const AryElemType* elem, + const ciArrayKlassMirror* klass, bool klass_is_exact, int instance_id) { + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset::bottom); + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset(0)); + fill_samples_helper(res, sample_idx, ptr, const_oop, elem, klass, klass_is_exact, instance_id, Type::Offset(1)); + }; + + for (auto& sample : _1d_samples) { + if (sample.ptr() == TypePtr::Constant && sample.const_oop().idx() == 0 && sample.offset() == 0) { + bool klass_is_exact = is_java_primitive(sample.elem()->basic_type()); + TypeAryMirror ary(sample.elem(), ArySizeType::BOTTOM); + auto elem_ptr_type = TypeAryPtrMirror::make(TypePtr::BotPTR, nullptr, ary, sample.klass(), klass_is_exact, Type::Offset(0), Type::Offset::bottom, TypeOopPtr::InstanceBot); + auto elem = AryElemType::find_2d(T_OBJECT, elem_ptr_type); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, true, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, TypeOopPtr::InstanceBot); + + auto& ci_ary_klass = ciArrayKlassMirror::find(T_OBJECT, sample.const_oop().klass()); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, ci_ary_klass.instance_id()); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, true, ci_ary_klass.instance_id() + 1); + + InstanceMirror const_oop_0(ci_ary_klass, 0); + fill_result(TypePtr::Constant, const_oop_0, elem, nullptr, true, TypeOopPtr::InstanceBot); + InstanceMirror const_oop_1(ci_ary_klass, 1); + fill_result(TypePtr::Constant, const_oop_1, elem, nullptr, true, TypeOopPtr::InstanceBot); + } + + if (sample.ptr() == TypePtr::BotPTR && sample.size() == ArySizeType::BOTTOM && !sample.klass_is_exact() && sample.offset() == 0) { + auto elem = AryElemType::find_2d(T_OBJECT, &sample); + fill_result(TypePtr::BotPTR, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + fill_result(TypePtr::NotNull, nullptr, elem, nullptr, false, TypeOopPtr::InstanceBot); + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeAryPtrMirror::_2d_samples = generate_2d_samples(); + +class TypeKlassPtrMirror : public TypePtrMirror { +private: + InterfaceSet _interfaces; + +protected: + constexpr TypeKlassPtrMirror(Type::TYPES base, TypePtr::PTR ptr, InterfaceSet interfaces, Type::Offset offset) + : TypePtrMirror(base, ptr, offset), _interfaces(interfaces) {} + +public: + static constexpr bool is_oopptr_type = false; + using InstType = TypeInstKlassPtrMirror; + using AryType = TypeAryKlassPtrMirror; + + constexpr InterfaceSet interfaces() const { return _interfaces; } + constexpr bool klass_is_exact() const { return ptr() == TypePtr::Constant; } + + virtual const TypeKlassPtrMirror* is_klassptr() const { return this; } + virtual const TypeInstKlassPtrMirror* is_instklassptr() const = 0; + virtual const TypeAryKlassPtrMirror* is_aryklassptr() const = 0; +}; + +static constexpr size_t TypeInstKlassPtr_samples_size() { + size_t res = 0; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded() || ci_klass.is_interface()) { + continue; + } + + if (ci_klass.is_java_lang_Object()) { + // j.l.O has 2 additional constant klass pointers corresponding to the interfaces I0 and I1 + res += 11; + continue; + } + + // The constant instance + res += 1; + + // The non-exact-klass instances + if (ci_klass.interfaces()._i0 && ci_klass.interfaces()._i1) { + res += 2; + } else if (ci_klass.interfaces()._i0 || ci_klass.interfaces()._i1) { + res += 4; + } else { + res += 8; + } + } + + // Different offset values + return res * 3; +} + +class TypeInstKlassPtrMirror : public TypeKlassPtrMirror { +private: + const ciInstanceKlassMirror* _klass; + + static constexpr auto generate_samples(); + + constexpr TypeInstKlassPtrMirror(TypePtr::PTR ptr, const ciInstanceKlassMirror& klass, InterfaceSet interfaces, Type::Offset offset) + : TypeKlassPtrMirror(Type::InstKlassPtr, ptr, interfaces, offset), _klass(&klass) { + assert(klass.is_loaded() && !klass.is_interface(), ""); + } + +public: + static const std::array _samples; + + constexpr TypeInstKlassPtrMirror() : TypeKlassPtrMirror(Type::Bad, TypePtr::TopPTR, InterfaceSet(false, false), Type::Offset(0)), _klass(nullptr) {} + + static constexpr const TypeInstKlassPtrMirror* make(TypePtr::PTR ptr, const ciInstanceKlassMirror* klass, InterfaceSet interfaces, Type::Offset offset = Type::Offset(0), + TypePtr::FlatInArray flat_in_array = TypePtr::NotFlat) { + assert(flat_in_array == TypePtr::NotFlat, "unsupported"); + for (auto& sample : _samples) { + if (sample.ptr() == ptr && sample.instance_klass() == klass && sample.interfaces() == interfaces && sample.offset() == offset.get()) { + return &sample; + } + } + + ShouldNotReachHere(); + } + + constexpr const ciInstanceKlassMirror* instance_klass() const { return _klass; } + + virtual const TypeInstKlassPtrMirror* is_instklassptr() const override { return this; } + virtual const TypeAryKlassPtrMirror* is_aryklassptr() const override { ShouldNotReachHere(); } + + virtual void dump_on(outputStream& st) const override { + st.print("InstKlassPtr:"); + dump_ptr(st); + st.print(" - "); + instance_klass()->dump_on(st); + st.print("("); + interfaces().dump_on(st); + st.print(")"); + dump_offset(st); + } +}; + +constexpr auto TypeInstKlassPtrMirror::generate_samples() { + std::array res; + size_t sample_idx = 0; + auto fill_result = [&](TypePtr::PTR ptr, const ciInstanceKlassMirror& ci_klass, InterfaceSet interfaces) { + res[sample_idx] = TypeInstKlassPtrMirror(ptr, ci_klass, interfaces, Type::Offset::bottom); + sample_idx++; + res[sample_idx] = TypeInstKlassPtrMirror(ptr, ci_klass, interfaces, Type::Offset(0)); + sample_idx++; + res[sample_idx] = TypeInstKlassPtrMirror(ptr, ci_klass, interfaces, Type::Offset(1)); + sample_idx++; + }; + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded() || ci_klass.is_interface()) { + continue; + } + + if (ci_klass.is_java_lang_Object()) { + fill_result(TypePtr::Constant, ci_klass, InterfaceSet(false, false)); + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(false, false)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(false, false)); + fill_result(TypePtr::Constant, ci_klass, InterfaceSet(false, true)); + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(false, true)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(false, true)); + fill_result(TypePtr::Constant, ci_klass, InterfaceSet(true, false)); + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, false)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, false)); + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, true)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, true)); + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + fill_result(TypePtr::Constant, ci_klass, interfaces); + fill_result(TypePtr::BotPTR, ci_klass, interfaces); + fill_result(TypePtr::NotNull, ci_klass, interfaces); + if (!interfaces._i0) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, interfaces._i1)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, interfaces._i1)); + } + if (!interfaces._i1) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(interfaces._i0, true)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(interfaces._i0, true)); + } + if (!interfaces._i0 && !interfaces._i1) { + fill_result(TypePtr::BotPTR, ci_klass, InterfaceSet(true, true)); + fill_result(TypePtr::NotNull, ci_klass, InterfaceSet(true, true)); + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeInstKlassPtrMirror::_samples = generate_samples(); + +static constexpr size_t TypeAryKlassPtr_1d_elem_samples_size() { + size_t res = 0; + // Top, Bot, byte, int, float + res += 5; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded()) { + continue; + } + + // The constant instance + res += 1; + if (ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + if (interfaces._i0 && interfaces._i1) { + res += 1; + } else if (interfaces._i0 || interfaces._i1) { + res += 2; + } else { + res += 4; + } + } + + return res; +} + +static constexpr size_t TypeAryKlassPtr_1d_samples_constant_size() { + size_t res = 0; + // byte[], int[], float[] + res += 3; + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded()) { + continue; + } + + res += 1; + } + + return res; +} + +static constexpr size_t TypeAryKlassPtr_1d_samples_notnull_size() { + size_t res = 0; + // bot[], byte[], int[], float[] + res += 4; + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded()) { + continue; + } + + // The notnull instance with constant elem + res += 1; + + if (ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + if (interfaces._i0 && interfaces._i1) { + res += 1; + } else if (interfaces._i0 || interfaces._i1) { + res += 2; + } else { + res += 4; + } + } + + return res; +} + +// All test instances have is_flat() == false, is_not_flat() == true, is_null_free() == false, +// is_not_null_free() == true, is_atomic() == true, is_refined_type() == false. All other +// parameters are included exhaustively. +class TypeAryKlassPtrMirror : public TypeKlassPtrMirror { +private: + static constexpr size_t _1d_elem_samples_size = TypeAryKlassPtr_1d_elem_samples_size(); + static constexpr size_t _1d_samples_size = (TypeAryKlassPtr_1d_samples_constant_size() + TypeAryKlassPtr_1d_samples_notnull_size() * 2) * 3; + static constexpr size_t _2d_elem_samples_size = TypeAryKlassPtr_1d_samples_constant_size() + TypeAryKlassPtr_1d_samples_notnull_size(); + static constexpr size_t _2d_samples_size = (TypeAryKlassPtr_1d_samples_constant_size() * 3 + TypeAryKlassPtr_1d_samples_notnull_size() * 2) * 3; + + const AryElemType* _elem; + const ciArrayKlassMirror* _klass; + + constexpr TypeAryKlassPtrMirror(TypePtr::PTR ptr, const AryElemType* elem, const ciArrayKlassMirror* klass, Type::Offset offset) + : TypeKlassPtrMirror(TypePtr::AryKlassPtr, ptr, _array_interfaces, offset), _elem(elem), _klass(klass) { + assert(elem != nullptr, ""); + assert((elem->base() == Type::Int) == (klass != nullptr), "only have klass for int/char/byte/short arrays"); + assert(klass == nullptr || klass->elem_basic_type() == elem->basic_type(), "mismatched klass"); + } + + static constexpr auto generate_1d_elem_samples(); + static constexpr auto generate_1d_samples(); + static constexpr auto generate_2d_elem_samples(); + static constexpr auto generate_2d_samples(); + +public: + static constexpr InterfaceSet _array_interfaces = TypeAryPtrMirror::_array_interfaces; + static const std::array, _1d_elem_samples_size> _1d_elem_samples; + static const std::array _1d_samples; + + static const std::array, _2d_elem_samples_size> _2d_elem_samples; + static const std::array _2d_samples; + + constexpr TypeAryKlassPtrMirror() : TypeKlassPtrMirror(Type::Bad, TypePtr::TopPTR, _array_interfaces, Type::Offset(0)), _elem(nullptr), _klass(nullptr) {} + + static const TypeAryKlassPtrMirror* make(TypePtr::PTR ptr, const AryElemType* elem, const ciArrayKlassMirror* klass, Type::Offset offset, + bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined) { + assert(!flat && not_flat && !null_free && not_null_free && atomic && !refined, "unsupported"); + for (auto& sample : _1d_samples) { + if (sample.ptr() == ptr && sample.elem() == elem && sample.klass() == klass && sample.offset() == offset.get()) { + return &sample; + } + } + + for (auto& sample : _2d_samples) { + if (sample.ptr() == ptr && sample.elem() == elem && sample.klass() == klass && sample.offset() == offset.get()) { + return &sample; + } + } + + ShouldNotReachHere(); + } + + const AryElemType* elem() const { return _elem; } + const ciArrayKlassMirror* klass() const { return _klass; } + + bool is_flat() const { return false; } + bool is_not_flat() const { return true; } + bool is_null_free() const { return false; } + bool is_not_null_free() const { return true; } + bool is_atomic() const { return true; } + bool is_refined_type() const { return false; } + + virtual const TypeInstKlassPtrMirror* is_instklassptr() const override { ShouldNotReachHere(); } + virtual const TypeAryKlassPtrMirror* is_aryklassptr() const override { return this; } + + virtual void dump_on(outputStream& st) const override { + st.print("AryKlassPtr:"); + dump_ptr(st); + st.print(" - "); + if (elem()->base() == Type::Bottom) { + st.print("bot[]"); + } else if (BasicType elem_bt = elem()->basic_type(); is_java_primitive(elem_bt)) { + st.print("%s[]", type2name(elem_bt)); + } else { + st.print("("); + elem()->make_ptr()->dump_on(st); + st.print(")[]"); + } + dump_offset(st); + } +}; + +template <> +constexpr const AryElemType* AryElemType::TOP = &TypeAryKlassPtrMirror::_1d_elem_samples[0]; + +template <> +constexpr const AryElemType* AryElemType::BOTTOM = &TypeAryKlassPtrMirror::_1d_elem_samples[1]; + +template <> +constexpr const AryElemType* AryElemType::find_1d(BasicType bt, const TypeKlassPtrMirror* ptr_type) { + for (auto& sample : TypeAryKlassPtrMirror::_1d_elem_samples) { + if (sample._bt == bt && sample._ptr_type == ptr_type) { + return &sample; + } + } + return nullptr; +} + +template <> +constexpr const AryElemType* AryElemType::find_2d(BasicType bt, const TypeKlassPtrMirror* ptr_type) { + for (auto& sample : TypeAryKlassPtrMirror::_2d_elem_samples) { + if (sample._bt == bt && sample._ptr_type == ptr_type) { + return &sample; + } + } + return nullptr; +} + +constexpr auto TypeAryKlassPtrMirror::generate_1d_elem_samples() { + std::array, _1d_elem_samples_size> res; + res[0] = AryElemType(T_ILLEGAL, nullptr); + res[1] = AryElemType(T_VOID, nullptr); + res[2] = AryElemType(T_BYTE, nullptr); + res[3] = AryElemType(T_INT, nullptr); + res[4] = AryElemType(T_FLOAT, nullptr); + + size_t sample_idx = 5; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded()) { + continue; + } + + if (ci_klass.is_interface()) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::Constant, ciEnvMirror::current()->Object_klass(), ci_klass.interfaces())); + sample_idx++; + } else { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::Constant, &ci_klass, ci_klass.interfaces())); + sample_idx++; + } + } + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + if (!ci_klass.is_loaded() || ci_klass.is_interface()) { + continue; + } + + InterfaceSet interfaces = ci_klass.interfaces(); + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::NotNull, &ci_klass, interfaces)); + sample_idx++; + if (!interfaces._i0) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::NotNull, &ci_klass, InterfaceSet(true, interfaces._i1))); + sample_idx++; + } + if (!interfaces._i1) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::NotNull, &ci_klass, InterfaceSet(interfaces._i0, true))); + sample_idx++; + } + if (!interfaces._i0 && !interfaces._i1) { + res[sample_idx] = AryElemType(T_OBJECT, TypeInstKlassPtrMirror::make(TypePtr::NotNull, &ci_klass, InterfaceSet(true, true))); + sample_idx++; + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array, TypeAryKlassPtrMirror::_1d_elem_samples_size> TypeAryKlassPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); + +constexpr auto TypeAryKlassPtrMirror::generate_1d_samples() { + std::array res; + size_t sample_idx = 0; + auto fill_result = [&](TypePtr::PTR ptr, const AryElemType* elem, const ciArrayKlassMirror* klass) { + res[sample_idx] = TypeAryKlassPtrMirror(ptr, elem, klass, Type::Offset::bottom); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(ptr, elem, klass, Type::Offset(0)); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(ptr, elem, klass, Type::Offset(1)); + sample_idx++; + }; + + fill_result(TypePtr::BotPTR, AryElemType::find_1d(T_VOID, nullptr), nullptr); + fill_result(TypePtr::NotNull, AryElemType::find_1d(T_VOID, nullptr), nullptr); + + auto& byte_ary_klass = ciArrayKlassMirror::find(T_BYTE, nullptr); + fill_result(TypePtr::BotPTR, AryElemType::find_1d(T_BYTE, nullptr), &byte_ary_klass); + fill_result(TypePtr::NotNull, AryElemType::find_1d(T_BYTE, nullptr), &byte_ary_klass); + fill_result(TypePtr::Constant, AryElemType::find_1d(T_BYTE, nullptr), &byte_ary_klass); + + auto& int_ary_klass = ciArrayKlassMirror::find(T_INT, nullptr); + fill_result(TypePtr::BotPTR, AryElemType::find_1d(T_INT, nullptr), &int_ary_klass); + fill_result(TypePtr::NotNull, AryElemType::find_1d(T_INT, nullptr), &int_ary_klass); + fill_result(TypePtr::Constant, AryElemType::find_1d(T_INT, nullptr), &int_ary_klass); + + fill_result(TypePtr::BotPTR, AryElemType::find_1d(T_FLOAT, nullptr), nullptr); + fill_result(TypePtr::NotNull, AryElemType::find_1d(T_FLOAT, nullptr), nullptr); + fill_result(TypePtr::Constant, AryElemType::find_1d(T_FLOAT, nullptr), nullptr); + + for (auto& elem : _1d_elem_samples) { + if (elem.make_ptr() == nullptr) { + continue; + } + + fill_result(TypePtr::BotPTR, &elem, nullptr); + fill_result(TypePtr::NotNull, &elem, nullptr); + + if (elem.make_ptr()->ptr() == TypePtr::Constant) { + fill_result(TypePtr::Constant, &elem, nullptr); + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeAryKlassPtrMirror::_1d_samples = generate_1d_samples(); + +constexpr auto TypeAryKlassPtrMirror::generate_2d_elem_samples() { + std::array, _2d_elem_samples_size> res; + size_t sample_idx = 0; + for (auto& ptr_type : _1d_samples) { + if (ptr_type.ptr() == TypePtr::BotPTR || ptr_type.offset() != 0) { + continue; + } + + res[sample_idx] = AryElemType(T_OBJECT, &ptr_type); + sample_idx++; + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array, TypeAryKlassPtrMirror::_2d_elem_samples_size> TypeAryKlassPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); + +constexpr auto TypeAryKlassPtrMirror::generate_2d_samples() { + std::array res; + size_t sample_idx = 0; + for (auto& elem : _2d_elem_samples) { + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::BotPTR, &elem, nullptr, Type::Offset::bottom); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::BotPTR, &elem, nullptr, Type::Offset(0)); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::BotPTR, &elem, nullptr, Type::Offset(1)); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::NotNull, &elem, nullptr, Type::Offset::bottom); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::NotNull, &elem, nullptr, Type::Offset(0)); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::NotNull, &elem, nullptr, Type::Offset(1)); + sample_idx++; + + if (elem.make_ptr()->ptr() == TypePtr::Constant) { + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::Constant, &elem, nullptr, Type::Offset::bottom); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::Constant, &elem, nullptr, Type::Offset(0)); + sample_idx++; + res[sample_idx] = TypeAryKlassPtrMirror(TypePtr::Constant, &elem, nullptr, Type::Offset(1)); + sample_idx++; + } + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array TypeAryKlassPtrMirror::_2d_samples = generate_2d_samples(); + +// OopPtrMirror is the mirror of oop +class OopPtrMirror { +private: + static constexpr size_t _samples_size = (ciInstanceKlassMirror::_samples.size() + ciArrayKlassMirror::_samples.size()) * 18 + 3; + InstanceMirror _pointee; + int _instance_id; + int _offset; + + constexpr OopPtrMirror(InstanceMirror pointee, int instance_id, int offset) : _pointee(pointee), _instance_id(instance_id), _offset(offset) {} + + static constexpr auto generate_samples(); + +public: + static const std::array _samples; + + constexpr OopPtrMirror() : _pointee(nullptr), _instance_id(0), _offset(0) {} + + template + static bool klass_satisfies(const ciKlassMirror* klass, const PtrType* type, bool type_is_exact) { + type_is_exact |= type->klass_is_exact(); + + if (klass->is_inst()) { + if (type->base() == Type::AryPtr || type->base() == Type::AryKlassPtr) { + return false; + } + + auto inst_klass = klass->as_inst(); + auto inst_interfaces = inst_klass->interfaces(); + if (inst_klass->is_interface()) { + inst_klass = ciEnvMirror::current()->Object_klass(); + } + + const typename PtrType::InstType* type_inst; + if constexpr (PtrType::is_oopptr_type) { + type_inst = type->is_oopptr()->is_instptr(); + } else { + type_inst = type->is_klassptr()->is_instklassptr(); + } + + if (type_is_exact) { + return inst_klass == type_inst->instance_klass() && + inst_interfaces == type_inst->interfaces(); + } else { + return inst_klass->is_subtype_of(type_inst->instance_klass()) && + inst_interfaces->contains(type_inst->interfaces()); + } + } + + if (type->base() == Type::InstPtr || type->base() == Type::InstKlassPtr) { + const typename PtrType::InstType* type_inst; + if constexpr (PtrType::is_oopptr_type) { + type_inst = type->is_oopptr()->is_instptr(); + } else { + type_inst = type->is_klassptr()->is_instklassptr(); + } + + return !type_is_exact && type_inst->instance_klass()->is_java_lang_Object() && + TypeAryKlassPtrMirror::_array_interfaces.contains(type_inst->interfaces()); + } + + const typename PtrType::AryType* type_ary; + if constexpr (PtrType::is_oopptr_type) { + type_ary = type->is_oopptr()->is_aryptr(); + } else { + type_ary = type->is_klassptr()->is_aryklassptr(); + } + auto type_elem = type_ary->elem(); + auto ary_klass = klass->as_ary(); + if (type_elem->base() == Type::Bottom) { + assert(type->ptr() != TypePtr::Constant, "cannot have an exact bot[]"); + return true; + } + + if (type_elem->basic_type() != ary_klass->elem_basic_type()) { + return false; + } + + if (type_elem->basic_type() != T_OBJECT) { + return true; + } else { + return klass_satisfies(ary_klass->elem(), type_elem->make_ptr(), type_is_exact); + } + } + + bool satisfies(const TypePtrMirror* type) const { + if (type->offset() != Type::OffsetBot && type->offset() != _offset) { + return false; + } + + if (_pointee.klass() == nullptr) { + return type->ptr() == TypePtr::BotPTR || type->ptr() == TypePtr::Null; + } + + if (type->base() == Type::AnyPtr) { + assert(type->ptr() == TypePtr::TopPTR || type->ptr() == TypePtr::Null, "must be top or null"); + return false; + } + assert(type->ptr() == TypePtr::BotPTR || type->ptr() == TypePtr::NotNull || type->ptr() == TypePtr::Constant, "only AnyPtr can be top or null"); + + auto type_oop = type->is_oopptr(); + if (_pointee.klass()->is_ary() && type->base() == Type::AryPtr && + !type_oop->is_aryptr()->size()->contains(_pointee.array_length())) { + return false; + } + + if (type->ptr() == TypePtr::Constant) { + auto const_oop = type_oop->const_oop(); + return const_oop == _pointee; + } + + if (type_oop->instance_id() != TypeOopPtr::InstanceBot && type_oop->instance_id() != _instance_id) { + return false; + } + + return klass_satisfies(_pointee.klass(), type_oop, false); + } + + void dump_on(outputStream& st) const { + st.print("klassptr_instance:"); + if (_pointee.klass() == nullptr) { + st.print("null"); + } else { + _pointee.klass()->dump_on(st); + st.print(" - idx=%d - instance_id=%d", _pointee.idx(), _instance_id); + } + st.print(" - offset=%d", _offset); + } +}; + +constexpr auto OopPtrMirror::generate_samples() { + std::array res; + res[0] = OopPtrMirror(InstanceMirror(nullptr), 0, 0); + res[1] = OopPtrMirror(InstanceMirror(nullptr), 0, 1); + res[2] = OopPtrMirror(InstanceMirror(nullptr), 0, 2); + + size_t sample_idx = 3; + auto fill_result_helper = [&](const ciKlassMirror& ci_klass, int idx, int instance_id) { + res[sample_idx] = OopPtrMirror(InstanceMirror(ci_klass, idx), instance_id, 0); + sample_idx++; + res[sample_idx] = OopPtrMirror(InstanceMirror(ci_klass, idx), instance_id, 1); + sample_idx++; + res[sample_idx] = OopPtrMirror(InstanceMirror(ci_klass, idx), instance_id, 2); + sample_idx++; + }; + + auto fill_result = [&](const ciKlassMirror& ci_klass) { + fill_result_helper(ci_klass, 0, 0); + fill_result_helper(ci_klass, 1, 0); + fill_result_helper(ci_klass, 2, 0); + fill_result_helper(ci_klass, 3, ci_klass.instance_id()); + fill_result_helper(ci_klass, 3, ci_klass.instance_id() + 1); + fill_result_helper(ci_klass, 3, ci_klass.instance_id() + 2); + }; + + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + fill_result(ci_klass); + } + for (auto& ci_klass : ciArrayKlassMirror::_samples) { + fill_result(ci_klass); + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array OopPtrMirror::_samples = generate_samples(); + +// KlassPtrMirror is the mirror of Klass* +class KlassPtrMirror { +private: + static constexpr size_t _samples_size = (ciInstanceKlassMirror::_samples.size() + ciArrayKlassMirror::_samples.size() + 1) * 3; + const ciKlassMirror* _klass; + int _offset; + + constexpr KlassPtrMirror(const ciKlassMirror* klass, int offset) : _klass(klass), _offset(offset) {} + + static constexpr auto generate_samples(); + +public: + static const std::array _samples; + + constexpr KlassPtrMirror() : _klass(nullptr), _offset(0) {} + + bool satisfies(const TypePtrMirror* type) const { + if (type->offset() != _offset && type->offset() != Type::OffsetBot) { + return false; + } + + if (_klass == nullptr) { + return type->ptr() == TypePtr::BotPTR || type->ptr() == TypePtr::Null; + } + + if (type->base() == Type::AnyPtr) { + assert(type->ptr() == TypePtr::TopPTR || type->ptr() == TypePtr::Null, "must be top or null"); + return false; + } + + assert(type->ptr() == TypePtr::BotPTR || type->ptr() == TypePtr::NotNull || type->ptr() == TypePtr::Constant, "only AnyPtr can be top or null"); + return OopPtrMirror::klass_satisfies(_klass, type->is_klassptr(), false); + } + + void dump_on(outputStream& st) const { + st.print("klassptr_instance:"); + if (_klass == nullptr) { + st.print("null"); + } else { + _klass->dump_on(st); + } + st.print(" - offset=%d", _offset); + } +}; + +constexpr auto KlassPtrMirror::generate_samples() { + std::array res; + res[0] = KlassPtrMirror(nullptr, 0); + res[1] = KlassPtrMirror(nullptr, 1); + res[2] = KlassPtrMirror(nullptr, 2); + + size_t sample_idx = 3; + for (auto& ci_klass : ciInstanceKlassMirror::_samples) { + res[sample_idx] = KlassPtrMirror(&ci_klass, 0); + res[sample_idx + 1] = KlassPtrMirror(&ci_klass, 1); + res[sample_idx + 2] = KlassPtrMirror(&ci_klass, 2); + sample_idx += 3; + } + for (auto& ci_klass : ciArrayKlassMirror::_samples) { + res[sample_idx] = KlassPtrMirror(&ci_klass, 0); + res[sample_idx + 1] = KlassPtrMirror(&ci_klass, 1); + res[sample_idx + 2] = KlassPtrMirror(&ci_klass, 2); + sample_idx += 3; + } + + assert(sample_idx == res.size(), ""); + return res; +} + +constexpr std::array KlassPtrMirror::_samples = generate_samples(); + +template +static void test_meet_join() { + constexpr size_t samples_size = PtrType::InstType::_samples.size() + PtrType::AryType::_1d_samples.size() + PtrType::AryType::_2d_samples.size(); + if constexpr (PtrType::is_oopptr_type) { + static_assert(samples_size == 2040); + } else { + static_assert(samples_size == 471); + } + + // Running all instances takes a lot of time, so we only run a fraction of them regularly + auto sample_hit = [] { + constexpr double sampling_prob = 0.02; + return uint(os::random()) < max_juint * sampling_prob; + }; + + GrowableArray type_samples(samples_size, MemTag::mtOther); + for (auto& sample : PtrType::InstType::_samples) { + if (sample_hit()) { + type_samples.append(&sample); + } + } + for (auto& sample : PtrType::AryType::_1d_samples) { + if (sample_hit()) { + type_samples.append(&sample); + } + } + for (auto& sample : PtrType::AryType::_2d_samples) { + if (sample_hit()) { + type_samples.append(&sample); + } + } + + for (int i = 0; i < type_samples.length(); i++) { + const PtrType* t1 = type_samples.at(i); + for (int j = i; j < type_samples.length(); j++) { + const PtrType* t2 = type_samples.at(j); + auto meet = TypeJavaPtrMeetHelper::javaptr_type_xmeet(t1, t2); + auto join = TypeJavaPtrJoinHelper::javaptr_type_xjoin(t1, t2); + + // Commutativity + ASSERT_EQ(TypeJavaPtrMeetHelper::javaptr_type_xmeet(t2, t1), meet); + ASSERT_EQ(TypeJavaPtrJoinHelper::javaptr_type_xjoin(t2, t1), join); + + // Verify that t1 and t2 must be subsets of meet + ASSERT_EQ(TypeJavaPtrMeetHelper::javaptr_type_xmeet(t1, meet), meet); + ASSERT_EQ(TypeJavaPtrMeetHelper::javaptr_type_xmeet(t2, meet), meet); + ASSERT_EQ(TypeJavaPtrJoinHelper::javaptr_type_xjoin(t1, meet), t1); + ASSERT_EQ(TypeJavaPtrJoinHelper::javaptr_type_xjoin(t2, meet), t2); + + if (join->base() != Type::AnyPtr) { + const PtrType* typed_join; + if constexpr (PtrType::is_oopptr_type) { + typed_join = join->is_oopptr(); + } else { + typed_join = join->is_klassptr(); + } + + // Verify that join must be a subset of both t1 and t2 + ASSERT_EQ(TypeJavaPtrMeetHelper::javaptr_type_xmeet(t1, typed_join), t1); + ASSERT_EQ(TypeJavaPtrMeetHelper::javaptr_type_xmeet(t2, typed_join), t2); + ASSERT_EQ(TypeJavaPtrJoinHelper::javaptr_type_xjoin(t1, typed_join), typed_join); + ASSERT_EQ(TypeJavaPtrJoinHelper::javaptr_type_xjoin(t2, typed_join), typed_join); + } + + // Element-wise verification + for (auto& elem : Ptr::_samples) { + bool in_t1 = elem.satisfies(t1); + bool in_t2 = elem.satisfies(t2); + bool in_meet = elem.satisfies(meet); + bool in_join = elem.satisfies(join); + + ASSERT_TRUE((!in_t1 && !in_t2) || in_meet); + ASSERT_EQ(in_t1 && in_t2, in_join); + } + } + } +} + +TEST(opto, typejavaptr) { + test_meet_join(); + test_meet_join(); +} diff --git a/test/hotspot/jtreg/compiler/types/TestMeetInstanceId.java b/test/hotspot/jtreg/compiler/types/TestMeetInstanceId.java new file mode 100644 index 000000000000..9c6fcd01e07c --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestMeetInstanceId.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package compiler.types; + +/* + * @test + * @bug 8370914 + * @summary C2 incorrectly computes the instance id of a meet, leading to symmetry assert. + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileThreshold=1 -XX:+UnlockDiagnosticVMOptions + * -XX:+StressIncrementalInlining -XX:TypeProfileLevel=200 + * -XX:CompileOnly=${test.main.class}::test ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileThreshold=1 -XX:+UnlockDiagnosticVMOptions + * -XX:+StressIncrementalInlining -XX:TypeProfileLevel=200 -XX:StressSeed=823469094 + * -XX:CompileOnly=${test.main.class}::test ${test.main.class} + */ +public class TestMeetInstanceId { + static Object getString() { + return "42"; + } + + static Object profileObject(Object obj) { + return obj; + } + + static Object test(boolean b) { + if (b) { + return null; + } + return profileObject(getString()); + } + + public static void main(String[] args) { + Object[] array = new Object[0]; + for (int i = 0; i < 20_000; i++) { + profileObject(array); + } + + test(true); + test(true); + } +} diff --git a/test/hotspot/jtreg/compiler/types/TestSameArrayDifferentViews.java b/test/hotspot/jtreg/compiler/types/TestSameArrayDifferentViews.java new file mode 100644 index 000000000000..5de22def6877 --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestSameArrayDifferentViews.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package compiler.types; + +import jdk.internal.vm.annotation.Stable; + +/* + * @test + * @bug 8370914 + * @summary The same constant array can be assigned to different variables with different Stable + * presence. + * @modules java.base/jdk.internal.vm.annotation + * @run main/bootclasspath/othervm -XX:-TieredCompilation -Xcomp + * -XX:CompileOnly=${test.main.class}::test ${test.main.class} + */ +public class TestSameArrayDifferentViews { + + @Stable + private static final int[] STABLE_VIEW = new int[3]; + + private static final int[] NON_STABLE_VIEW = STABLE_VIEW; + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + test(true); + test(false); + } + } + + private static int[] test(boolean b) { + return b ? STABLE_VIEW : NON_STABLE_VIEW; + } +} diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java index 9f8242cdd9e9..3c16a96ef1cc 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java @@ -979,7 +979,7 @@ public void test28_verifier() { } @Test - @IR(failOn = {ALLOC_ARRAY_OF_MYVALUE_KLASS, LOOP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) + @IR(failOn = {LOOP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) @IR(failOn = LOAD_OF_ANY_KLASS, applyIf = {"InlineTypeReturnedAsFields", "false"}) @IR(counts = {LOAD_OF_ANY_KLASS, "4"}, applyIf = {"InlineTypeReturnedAsFields", "true"}) public MyValue2 test29(MyValue2[] src) { From 19290619920c478590c11b1b21eb5909f74b5310 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 24 Aug 2026 06:49:03 +0000 Subject: [PATCH 040/223] 8390650: Unsafe access with constant zero offset triggers assert in EA Reviewed-by: qamai, kvn --- src/hotspot/share/opto/escape.cpp | 5 +- .../TestUnsafeAccessWithZeroOffset.java | 95 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/TestUnsafeAccessWithZeroOffset.java diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 957b79caf1fe..2564ce20b4d3 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -169,10 +169,11 @@ bool ConnectionGraph::compute_escape() { java_objects_worklist.append(phantom_obj); for( uint next = 0; next < ideal_nodes.size(); ++next ) { Node* n = ideal_nodes.at(next); - if ((n->Opcode() == Op_LoadX || n->Opcode() == Op_StoreX) && + if (n->is_Mem() && !n->in(MemNode::Address)->is_AddP() && _igvn->type(n->in(MemNode::Address))->isa_oopptr()) { - // Load/Store at mark work address is at offset 0 so has no AddP which confuses EA + // EA expects on-heap memory addresses to be represented by an AddP. An AddP with a zero + // offset can be optimized to its oop base, so recreate it. Node* addp = AddPNode::make_with_base(n->in(MemNode::Address), n->in(MemNode::Address), _igvn->MakeConX(0)); _igvn->register_new_node_with_optimizer(addp); _igvn->replace_input_of(n, MemNode::Address, addp); diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestUnsafeAccessWithZeroOffset.java b/test/hotspot/jtreg/compiler/intrinsics/TestUnsafeAccessWithZeroOffset.java new file mode 100644 index 000000000000..627b465cee7d --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestUnsafeAccessWithZeroOffset.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8390650 + * @summary Test unreachable unsafe accesses at offset zero. + * @requires vm.compiler2.enabled + * @modules java.base/jdk.internal.misc + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=delayinline,${test.main.class}::getOffset + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + */ + +import jdk.internal.misc.Unsafe; + +public class TestUnsafeAccessWithZeroOffset { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + static Object testPlain(Object obj, Object x, boolean b) { + Object unused = new Object(); // Trigger EA + long offset = getOffset(); + if (b) { + // Never reached + Object result = UNSAFE.getReference(obj, 0L); + UNSAFE.putReference(obj, offset, x); + return result; + } + return null; + } + + static Object testLoadStore(Object obj, Object expected, Object x, boolean b) { + Object unused = new Object(); // Trigger EA + if (b) { + // Never reached + return UNSAFE.compareAndExchangeReference(obj, 0L, expected, x); + } + return null; + } + + static long getOffset() { + return 0L; + } + + static Object testPlainDelayed(Object obj, Object x, boolean b) { + Object unused = new Object(); // Trigger EA + long offset = getOffset(); + if (b) { + // Never reached + Object result = UNSAFE.getReference(obj, offset); + UNSAFE.putReference(obj, offset, x); + return result; + } + return null; + } + + static Object testLoadStoreDelayed(Object obj, Object expected, Object x, boolean b) { + Object unused = new Object(); // Trigger EA + long offset = getOffset(); + if (b) { + // Never reached + return UNSAFE.compareAndExchangeReference(obj, offset, expected, x); + } + return null; + } + + public static void main(String[] args) { + Object value = new Object(); + testPlain(value, value, false); + testLoadStore(value, value, value, false); + testPlainDelayed(value, value, false); + testLoadStoreDelayed(value, value, value, false); + } +} + From a7977b847e18675428eb07dc7df172bfbd7e1669 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 24 Aug 2026 06:49:31 +0000 Subject: [PATCH 041/223] 8357381: C2: assert(false) failed: should not be here Co-authored-by: Saranya Natarajan Reviewed-by: kvn, qamai --- src/hotspot/share/opto/escape.cpp | 44 +++++++----- src/hotspot/share/opto/escape.hpp | 1 + .../TestReadOnlyStringIntrinsicDuringEA.java | 71 +++++++++++++++++++ 3 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestReadOnlyStringIntrinsicDuringEA.java diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 2564ce20b4d3..20c50a074442 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4518,10 +4518,8 @@ void ConnectionGraph::move_inst_mem(Node* n, Unique_Node_List& orig_phis) { if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) { continue; // Nothing to do } - // Replace previous general reference to mem node. - uint orig_uniq = C->unique(); - Node* m = find_inst_mem(n, general_idx, orig_phis); - assert(orig_uniq == C->unique(), "no new nodes"); + // Replace previous general reference to mem node and assert no new node is created. + Node* m = find_inst_mem_assert_no_new_node(n, general_idx, orig_phis); mmem->set_memory_at(general_idx, m); --imax; --i; @@ -4538,15 +4536,26 @@ void ConnectionGraph::move_inst_mem(Node* n, Unique_Node_List& orig_phis) { alias_idx == general_idx) { continue; // Nothing to do } - // Move to general memory slice. - uint orig_uniq = C->unique(); - Node* m = find_inst_mem(n, general_idx, orig_phis); - assert(orig_uniq == C->unique(), "no new nodes"); + // Move to general memory slice and assert no new node is created. + Node* m = find_inst_mem_assert_no_new_node(n, general_idx, orig_phis); igvn->hash_delete(use); imax -= use->replace_edge(n, m, igvn); igvn->hash_insert(use); record_for_optimizer(use); --i; + } else if (use->is_memory_access_intrinsic()) { + if (alias_idx == general_idx) { + continue; + } + if (use->in(MemNode::Memory) == n) { + // Move to general memory slice and assert no new node is created. + Node* m = find_inst_mem_assert_no_new_node(n, general_idx, orig_phis); + igvn->hash_delete(use); + imax -= use->replace_edge(n, m, igvn); + igvn->hash_insert(use); + record_for_optimizer(use); + --i; + } #ifdef ASSERT } else if (use->is_Mem()) { // Memory nodes should have new memory input. @@ -4790,6 +4799,13 @@ Node* ConnectionGraph::find_inst_mem(Node* orig_mem, int alias_idx, Unique_Node_ return result; } +Node* ConnectionGraph::find_inst_mem_assert_no_new_node(Node* orig_mem, int alias_idx, Unique_Node_List& orig_phis) { + uint orig_uniq = _compile->unique(); + Node* result = find_inst_mem(orig_mem, alias_idx, orig_phis); + assert(orig_uniq == _compile->unique(), "no new nodes"); + return result; +} + // // Convert the types of non-escaped object to instance types where possible, // propagate the new type information through the graph, and update memory @@ -5194,12 +5210,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // They overwrite memory edge corresponding to destination array, memnode_worklist.push(use); } else if (!(op == Op_CmpP || op == Op_Conv2B || - op == Op_CastP2X || - op == Op_FastLock || op == Op_AryEq || - op == Op_StrComp || op == Op_CountPositives || - op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || - op == Op_StrEquals || op == Op_VectorizedHashCode || - op == Op_StrIndexOf || op == Op_StrIndexOfChar || + op == Op_CastP2X || op == Op_FastLock || + use->is_memory_access_intrinsic() || op == Op_SubTypeCheck || op == Op_InlineType || op == Op_FlatArrayCheck || op == Op_ReinterpretS2HF || op == Op_ReachabilityFence || @@ -5390,9 +5402,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // They overwrite memory edge corresponding to destination array, memnode_worklist.push(use); } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) || - op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives || - op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || op == Op_VectorizedHashCode || - op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar || op == Op_FlatArrayCheck)) { + use->is_memory_access_intrinsic() || op == Op_FlatArrayCheck)) { n->dump(); use->dump(); assert(false, "EA: missing memory path"); diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 7303e20195e8..44f2d6aaa694 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -566,6 +566,7 @@ class ConnectionGraph: public ArenaObj { void move_inst_mem(Node* n, Unique_Node_List& orig_phis); bool flat_access_aliases_with(Node* flat_access, const TypeOopPtr *toop); Node* find_inst_mem(Node* mem, int alias_idx, Unique_Node_List& orig_phi_worklist, uint rec_depth = 0); + Node* find_inst_mem_assert_no_new_node(Node* mem, int alias_idx, Unique_Node_List& orig_phi_worklist); Node* step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop); Node_Array _node_map; // used for bookkeeping during type splitting diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestReadOnlyStringIntrinsicDuringEA.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReadOnlyStringIntrinsicDuringEA.java new file mode 100644 index 000000000000..d50a112cea7f --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReadOnlyStringIntrinsicDuringEA.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8357381 + * @summary C2 compilation fails with C2: assert(false) failed: should not be here + * @requires vm.compiler2.enabled + * @run main ${test.main.class} + * @run main/othervm -XX:-TieredCompilation -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + */ + +package compiler.escapeAnalysis; + +public class TestReadOnlyStringIntrinsicDuringEA { + static int test1(String id, String nameKey) { + try { + java.io.ByteArrayOutputStream stream = new java.io.ByteArrayOutputStream(); + java.math.BigInteger num = java.math.BigInteger.valueOf(123); + int length = num.toByteArray().length; + stream.write(num.toByteArray()); + } catch (Exception e) { + throw new RuntimeException(e); + } + if ("UTC".equals(id) && id.equals(nameKey)) { + } + return 0; + } + + static boolean test2(String b) { + String t1 = ""; + var s1 = new StringBuffer(); + var s2 = s1.append(String.valueOf(t1)); + var s3 = s2.append(7); + var s4 = String.valueOf("AB"); + var s5 = s4.equals(String.valueOf(b)); + return s5; + } + + public static void main(String[] strArr) { + for (int i = 0; i < 10_000; i++) { + new StringBuffer().append(i); + } + for (int t = 0; t < 50_000; t++) { + test1("123456abc", "123456abc"); + test2("X"); + } + } +} From 235cc881ae9c5c2accaed97be2be50aaacb93aa9 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 24 Aug 2026 07:00:26 +0000 Subject: [PATCH 042/223] 8390459: [Valhalla] compiler/valhalla/inlinetypes/TestArrays.java#id6 fails IR matching Reviewed-by: qamai, shade, chagedorn --- .../compiler/lib/ir_framework/Scenario.java | 11 +++ .../valhalla/inlinetypes/InlineTypes.java | 85 ++++++------------- .../valhalla/inlinetypes/TestArrays.java | 8 +- .../inlinetypes/TestArraysCopyOf.java | 8 +- .../valhalla/inlinetypes/TestIntrinsics.java | 4 +- .../valhalla/inlinetypes/TestLWorld.java | 4 +- .../inlinetypes/TestNullableArrays.java | 8 +- .../inlinetypes/TestNullableInlineTypes.java | 4 +- .../inlinetypes/TestValueClasses.java | 4 +- 9 files changed, 59 insertions(+), 77 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java index 4971b87a236d..014a65efc793 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java @@ -104,6 +104,17 @@ public void addFlags(String... flags) { } } + /** + * Prepend additional VM flags to this scenario. + * + * @param flags the additional scenario VM flags. + */ + public void prependFlags(String... flags) { + if (flags != null) { + this.flags.addAll(0, Arrays.asList(flags)); + } + } + /** * Get all scenario specific VM flags as defined in {@link #Scenario(int, String...)}. * diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java index 36575da28715..7a13e56d3bf8 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java @@ -34,30 +34,17 @@ public class InlineTypes { public static final Scenario[] DEFAULT_SCENARIOS = { new Scenario(0, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseACmpProfile", - "-XX:+AlwaysIncrementalInline", "-XX:FlatArrayElementMaxOops=5", "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields" + "-XX:+InlineTypeReturnedAsFields", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+AlwaysIncrementalInline" ), new Scenario(1, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseACmpProfile", "-XX:-UseCompressedOops", "-XX:FlatArrayElementMaxOops=5", @@ -68,13 +55,6 @@ public class InlineTypes { "-XX:-InlineTypeReturnedAsFields" ), new Scenario(2, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseACmpProfile", "-XX:-UseCompressedOops", "-XX:FlatArrayElementMaxOops=0", @@ -85,29 +65,16 @@ public class InlineTypes { "-XX:+InlineTypeReturnedAsFields" ), new Scenario(3, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-DVerifyIR=false", - "-XX:+AlwaysIncrementalInline", "-XX:FlatArrayElementMaxOops=0", "-XX:-UseArrayFlattening", "-XX:-UseFieldFlattening", "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields" + "-XX:+InlineTypeReturnedAsFields", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+AlwaysIncrementalInline" ), new Scenario(4, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-DVerifyIR=false", "-XX:FlatArrayElementMaxOops=-1", "-XX:+UseArrayFlattening", @@ -117,32 +84,18 @@ public class InlineTypes { "-XX:-ReduceInitialCardMarks" ), new Scenario(5, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseACmpProfile", - "-XX:+AlwaysIncrementalInline", "-XX:FlatArrayElementMaxOops=5", "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", "-XX:-InlineTypePassFieldsAsArgs", - "-XX:-InlineTypeReturnedAsFields" + "-XX:-InlineTypeReturnedAsFields", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+AlwaysIncrementalInline" ), new Scenario(6, - "--enable-preview", - "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", - "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseACmpProfile", - "-XX:+AlwaysIncrementalInline", "-XX:FlatArrayElementMaxOops=5", "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", @@ -151,10 +104,28 @@ public class InlineTypes { "-XX:+UseNullFreeAtomicValueFlattening", "-XX:+UseNullFreeNonAtomicValueFlattening", "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields" + "-XX:+InlineTypeReturnedAsFields", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+AlwaysIncrementalInline" ), }; + static { + // Add common flags + for (Scenario scenario : DEFAULT_SCENARIOS) { + scenario.prependFlags("--enable-preview", + "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+UnlockExperimentalVMOptions", + // Force inline the methods called by ValueClass::validateArrayArguments used by the array factories + "-XX:CompileCommand=inline,jdk.internal.value.ValueClass::isConcreteValueClass", + "-XX:CompileCommand=inline,java.lang.Class::isValue", + "-XX:CompileCommand=inline,java.lang.reflect.Modifier::isAbstract"); + } + } + public static TestFramework getFramework() { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); return new TestFramework(walker.getCallerClass()).setDefaultWarmup(251); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java index 4966465665c4..9d3a610e3a32 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java @@ -145,10 +145,10 @@ public class TestArrays { public static void main(String[] args) { Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[2].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); - scenarios[3].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:-UncommonNullCast"); - scenarios[4].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); - scenarios[5].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[2].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[3].addFlags("--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[4].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[5].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); InlineTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java index 7e0c3ad14937..134aba00aeff 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java @@ -120,10 +120,10 @@ public class TestArraysCopyOf { public static void main(String[] args) { Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[2].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); - scenarios[3].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:-UncommonNullCast"); - scenarios[4].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); - scenarios[5].addFlags("--enable-preview", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[2].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[3].addFlags("--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[4].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[5].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); String[] flagsForScenario = scenarios[Integer.parseInt(args[0])].getFlags().toArray(new String[0]); CompileFramework comp = new CompileFramework(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java index 23b42bad191b..e455d7ee68c8 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java @@ -155,8 +155,8 @@ public TestIntrinsics() { public static void main(String[] args) { Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[3].addFlags("-XX:-MonomorphicArrayCheck", "-XX:+UseArrayFlattening"); - scenarios[4].addFlags("-XX:-MonomorphicArrayCheck", "-XX:+UnlockExperimentalVMOptions", "-XX:PerMethodSpecTrapLimit=0", "-XX:PerMethodTrapLimit=0"); + scenarios[3].addFlags("-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); + scenarios[4].addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:PerMethodSpecTrapLimit=0", "-XX:PerMethodTrapLimit=0", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); InlineTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java index 513ee0c20644..f4187db48981 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java @@ -178,8 +178,8 @@ public static void main(String[] args) { class2.getDeclaredFields(); Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[3].addFlags("-XX:-MonomorphicArrayCheck", "-XX:+UseArrayFlattening"); - scenarios[4].addFlags("-XX:-MonomorphicArrayCheck"); + scenarios[3].addFlags("-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); + scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); InlineTypes.getFramework() // TODO 8337821: Temporarily increased MemLimit - remove again with JDK-8378328 once fixed. diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java index 3c16a96ef1cc..db0eb31fe491 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java @@ -136,10 +136,10 @@ public class TestNullableArrays { public static void main(String[] args) { Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[2].addFlags("-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); - scenarios[3].addFlags("-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); - scenarios[4].addFlags("-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); - scenarios[5].addFlags("-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[2].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); + scenarios[3].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); + scenarios[5].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); InlineTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java index 43446ec688d2..0a641ba2961a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java @@ -164,8 +164,8 @@ public TestNullableInlineTypes() { public static void main(String[] args) { Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; - scenarios[3].addFlags("-XX:-MonomorphicArrayCheck", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening"); - scenarios[4].addFlags("-XX:-MonomorphicArrayCheck"); + scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); + scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); InlineTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java index ebf246cd7d60..947082760288 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java @@ -129,8 +129,8 @@ public static void main(String[] args) { // Don't generate bytecodes but call through runtime for reflective calls scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000"); scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000"); - scenarios[3].addFlags("-XX:-MonomorphicArrayCheck", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening"); - scenarios[4].addFlags("-XX:-UseTLAB", "-XX:-MonomorphicArrayCheck"); + scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); + scenarios[4].addFlags("-XX:-UseTLAB", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); InlineTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) From ff9c82f202dde29224a7c3acb19a1646db6d7884 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 24 Aug 2026 07:13:05 +0000 Subject: [PATCH 043/223] 8389390: [Valhalla] Compile::adjust_flat_array_access_aliases asserts due SCMemProj Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/library_call.cpp | 15 +- .../CompareAndSetFlatArrayField.java | 169 ++++++++++++++++++ .../inlinetypes/TestFlatArrayCASAssert.java | 52 ++++++ 3 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index f91077c9e174..bbe3d184c4de 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2976,10 +2976,17 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt Compile::AliasType* alias_type = C->alias_type(adr_type); BasicType bt = alias_type->basic_type(); - if (bt != T_ILLEGAL && - (is_reference_type(bt) != (type == T_OBJECT))) { - // Don't intrinsify mismatched object accesses. - return false; + if (bt != T_ILLEGAL) { + if (adr_type->isa_aryptr() && adr_type->is_flat()) { + // mismatched access to a flat array element: + // type=T_OBJECT doesn't make sense (and breaks Compile::adjust_flat_array_access_aliases()). + // Some other type may need to be supported so this may need to be relaxed. + return false; + } + if (is_reference_type(bt) != (type == T_OBJECT)) { + // Don't intrinsify mismatched object accesses. + return false; + } } old_state.discard(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java new file mode 100644 index 000000000000..48ffe1626386 --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2026 IBM Corporation. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8389390 + * @summary [Valhalla] Compile::adjust_flat_array_access_aliases asserts due SCMemProj + * @enablePreview + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.value + * java.base/jdk.internal.vm.annotation + * @run main/othervm -XX:-BackgroundCompilation ${test.main.class} + */ + +package compiler.valhalla.inlinetypes; + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; +import jdk.internal.value.ValueClass; + +public class CompareAndSetFlatArrayField { + static public value class MyValue1 { + Object field; + MyValue1(Object v) { + field = v; + } + } + + static public value class MyValue2 { + int field; + MyValue2(int v) { + field = v; + } + } + + private static final Unsafe U = Unsafe.getUnsafe(); + + private static final MyValue1[] array1; + private static final long ARRAY1_BASE_OFFSET; + private static final int ARRAY1_INDEX_SCALE; + private static final boolean ARRAY1_FLATTENED; + private static final int ARRAY_LAYOUT1; + private static final long VALUE1_HEADER_SIZE; + private static final long VALUE1_FIELD_OFFSET; + + private static final MyValue2[] array2; + private static final long ARRAY2_BASE_OFFSET; + private static final int ARRAY2_INDEX_SCALE; + private static final boolean ARRAY2_FLATTENED; + private static final int ARRAY2_LAYOUT; + private static final long VALUE2_HEADER_SIZE; + private static final long FIELD_OFFSET2; + + private MyValue1 field1; + private static final boolean FLAT_FIELD1; + private static final long FIELD1_OFFSET; + private static final int FIELD1_LAYOUT; + + private MyValue2 field2; + private static final boolean FLAT_FIELD2; + private static final long FIELD2_OFFSET; + private static final int FIELD2_LAYOUT; + + private static Object o1 = new Object(); + private static Object o2 = new Object(); + + private static CompareAndSetFlatArrayField testObject = new CompareAndSetFlatArrayField(); + + static { + try { + array1 = (MyValue1[])ValueClass.newNullRestrictedNonAtomicArray(MyValue1.class, 1, new MyValue1(o1)); + ARRAY1_BASE_OFFSET = U.arrayInstanceBaseOffset(array1); + ARRAY1_INDEX_SCALE = U.arrayInstanceIndexScale(array1); + ARRAY1_FLATTENED = ValueClass.isFlatArray(array1); + ARRAY_LAYOUT1 = U.arrayLayout(array1); + VALUE1_HEADER_SIZE = U.valueHeaderSize(MyValue1.class); + Field f = MyValue1.class.getDeclaredField("field"); + VALUE1_FIELD_OFFSET = U.objectFieldOffset(f); + + array2 = (MyValue2[])ValueClass.newNullRestrictedNonAtomicArray(MyValue2.class, 1, new MyValue2(42)); + ARRAY2_BASE_OFFSET = U.arrayInstanceBaseOffset(array2); + ARRAY2_INDEX_SCALE = U.arrayInstanceIndexScale(array2); + ARRAY2_FLATTENED = ValueClass.isFlatArray(array2); + ARRAY2_LAYOUT = U.arrayLayout(array2); + VALUE2_HEADER_SIZE = U.valueHeaderSize(MyValue2.class); + f = MyValue2.class.getDeclaredField("field"); + FIELD_OFFSET2 = U.objectFieldOffset(f); + + f = CompareAndSetFlatArrayField.class.getDeclaredField("field1"); + FIELD1_OFFSET = U.objectFieldOffset(f); + FLAT_FIELD1 = U.isFlatField(f); + FIELD1_LAYOUT = U.fieldLayout(f); + + f = CompareAndSetFlatArrayField.class.getDeclaredField("field2"); + FIELD2_OFFSET = U.objectFieldOffset(f); + FLAT_FIELD2 = U.isFlatField(f); + FIELD2_LAYOUT = U.fieldLayout(f); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static public boolean test1(Object oldVal, Object newVal) { + array1[0] = new MyValue1(oldVal); + return U.compareAndSetReference(array1, ARRAY1_BASE_OFFSET, oldVal, newVal); + } + + static public boolean test2(int oldVal, int newVal) { + array2[0] = new MyValue2(oldVal); + return U.compareAndSetFlatValue(array2, ARRAY2_BASE_OFFSET, ARRAY2_LAYOUT, MyValue2.class, new MyValue2(oldVal), new MyValue2(newVal)); + } + + static public boolean test3(Object oldVal, Object newVal) { + testObject.field1 = new MyValue1(oldVal); + return U.compareAndSetReference(testObject, FIELD1_OFFSET, oldVal, newVal); + } + + static public boolean test4(int oldVal, int newVal) { + testObject.field2 = new MyValue2(oldVal); + return U.compareAndSetFlatValue(testObject, FIELD2_OFFSET, FIELD2_LAYOUT, MyValue2.class, new MyValue2(oldVal), new MyValue2(newVal)); + } + + static public void main(String args[]) { + if (!ARRAY1_FLATTENED || !ARRAY2_FLATTENED || !FLAT_FIELD1 || !FLAT_FIELD2) { + return; + } + if (VALUE1_FIELD_OFFSET != VALUE1_HEADER_SIZE) { + throw new RuntimeException("fix test: test assumes MyValue1[0].f is at offset 0 in MyValue1[0]"); + } + for (int i = 0; i < 20_000; i++) { + boolean res = test1(o1, o2); + if (!res) { + throw new RuntimeException("CAS failed"); + } + res = test2(42, 0x42); + if (!res) { + throw new RuntimeException("CAS failed"); + } + res = test3(o1, o2); + if (!res) { + throw new RuntimeException("CAS failed"); + } + res = test4(42, 0x42); + if (!res) { + throw new RuntimeException("CAS failed"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java new file mode 100644 index 000000000000..20e4a6facb66 --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +/* + * @test + * @bug 8389390 + * @summary [Valhalla] Compile::adjust_flat_array_access_aliases asserts due SCMemProj + * @enablePreview + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline ${test.main.class} + */ + +public class TestFlatArrayCASAssert { + static value class V { } + + static final VarHandle VH = MethodHandles.arrayElementVarHandle(V[].class); + + static void test() { + VH.getAndSet(new V[1], 0, null); + } + + public static void main(String[] args) { + for (int i = 0; i < 30_000; i++) { + if ((i & 255) == 0) { + test(); + } + } + } +} From 781c83c6e7d5e5954f4d7b79ee307a3fcfab321b Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Mon, 24 Aug 2026 07:31:41 +0000 Subject: [PATCH 044/223] 8390654: Test gc/TestUseGCOverheadLimit.java#G1 fails on linux-arm32 Reviewed-by: tschatzl, shade --- test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java b/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java index dcc501c7710a..ba253f3e8fc7 100644 --- a/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java +++ b/test/hotspot/jtreg/gc/TestUseGCOverheadLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.stream.Stream; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -62,8 +63,11 @@ public static void main(String args[]) throws Exception { String[] selectedArgs = args[0].equals("G1") ? g1Args : parallelArgs; + final String[] vm64bitArgs = { + "-XX:-UseCompactObjectHeaders" // Object sizes are calculated such that the heap is tight. + }; + final String[] commonArgs = { - "-XX:-UseCompactObjectHeaders", // Object sizes are calculated such that the heap is tight. "-XX:ParallelGCThreads=1", // Make GCs take longer. "-XX:+UseGCOverheadLimit", "-Xlog:gc=debug", @@ -72,7 +76,9 @@ public static void main(String args[]) throws Exception { Allocating.class.getName() }; - String[] vmArgs = Stream.concat(Arrays.stream(selectedArgs), Arrays.stream(commonArgs)).toArray(String[]::new); + String[] vmArgs = Stream.of(selectedArgs, Platform.is64bit() ? vm64bitArgs : new String[0], commonArgs) + .flatMap(Arrays::stream) + .toArray(String[]::new); OutputAnalyzer output = ProcessTools.executeLimitedTestJava(vmArgs); output.shouldNotHaveExitValue(0); From 4f0898a37a2b6ea82cff6e726f4d1eb32588951b Mon Sep 17 00:00:00 2001 From: Alessandro Autiero Date: Mon, 24 Aug 2026 08:16:13 +0000 Subject: [PATCH 045/223] 8373613: PEXT/PDEP intrinsics cause performance regression on AMD pre-Zen 3 CPUs Reviewed-by: jkarthikeyan, dlong, jbhateja --- src/hotspot/cpu/x86/vm_version_x86.cpp | 49 +++++++++++++++++++ src/hotspot/cpu/x86/vm_version_x86.hpp | 5 +- src/hotspot/cpu/x86/x86.ad | 2 +- .../c2/gvn/TestBitCompressValueTransform.java | 36 +++++++------- .../intrinsics/TestBitShuffleOpers.java | 4 +- .../test/ApplicableIRRulesPrinter.java | 1 + .../jdk/test/whitebox/CPUInfoTest.java | 4 +- 7 files changed, 77 insertions(+), 24 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index cfe0f91f0acd..bc882f395862 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1154,6 +1154,10 @@ void VM_Version::get_processor_features() { cpu_family(), _model, _stepping, os::cpu_microcode_revision()); ss.print(", "); int features_offset = (int)ss.size(); + if (compute_fast_bmi2()) { + _features.set_feature(CPU_FAST_BMI2); + } + insert_features_names(_features, ss); _cpu_info_string = ss.as_string(true); @@ -2007,6 +2011,51 @@ bool VM_Version::compute_has_intel_jcc_erratum() { } } +// The BMI2 instruction set includes PEXT (parallel bits extract) and PDEP +// (parallel bits deposit), which are used to intrinsify Integer/Long.compress +// and Integer/Long.expand (added in JDK 19, see https://bugs.openjdk.org/browse/JDK-8283893). +// +// While all BMI2-capable CPUs can execute these instructions, PEXT and PDEP +// are unique in that some vendors implement them via microcode rather than +// native ALU hardware. The microcoded versions are significantly slower (high latency/low throughput) +// than the manual bitwise fallback used in the Java implementation. +// Conversely, all other BMI2 instructions (BZHI, MULX, RORX, SARX, SHRX, SHLX) +// execute efficiently on every BMI2-capable CPU and are unaffected by this check. +// +// The logic in this method is based on official optimization guides from hardware vendors, +// to guarantee that microcode implementations of PEXT/PDEP are not used. +bool VM_Version::compute_fast_bmi2() { + if (!supports_bmi2()) { + return false; + } + + if (is_intel()) { + // All Intel CPUs with BMI2 (Haswell+) implement PEXT/PDEP natively. + // 3-cycle latency, 1-per-cycle throughput on a dedicated ALU port. + // Source: Intel Intrinsics Guide, https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html + return true; + } + + if (is_amd()) { + // AMD added BMI2 in Excavator (Family 0x15, model 0x60+) but used + // microcode for PEXT/PDEP through all of Zen 2 (Family 0x17). + // Native ALU hardware support arrived with Zen 3 (Family 0x19). + // Source: AMD Software Optimization Guide (doc #56665), Section 2.10.2, https://developer.amd.com/resources/developer-guides-manuals/ + uint32_t family = extended_cpu_family(); + return family >= CPU_FAMILY_AMD_19H; + } + + // Zhaoxin added BMI2 support in Lujiazui (KX-6000+). + // Based on community benchmarks(https://uops.info/html-instr/PDEP_R64_R64_R64.html), + // PEXT/PDEP performance is known to be similarly poor to pre-Zen3 AMD, suggesting a microcode implementation. + // This cannot be confirmed as Zhaoxin publishes no public optimization guide. + + // On VIA/Centaur CNS, BMI2 is implemented in hardware with PDEP/PEXT executing at two per cycle (better than Haswell). + // Intel acquired Centaur in 2021, and CNS never reached production, so we don't check for it. + + return false; +} + // On Xen, the cpuid instruction returns // eax / registers[0]: Version of Xen // ebx / registers[1]: chars 'XenV' diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index d268665d0910..459180b2fe62 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -439,7 +439,8 @@ class VM_Version : public Abstract_VM_Version { decl(AVX512_FP16, avx512_fp16 ) /* AVX512 FP16 ISA support*/ \ decl(AVX10_1, avx10_1 ) /* AVX10 512 bit vector ISA Version 1 support*/ \ decl(AVX10_2, avx10_2 ) /* AVX10 512 bit vector ISA Version 2 support*/ \ - decl(HYBRID, hybrid ) /* Hybrid architecture */ + decl(HYBRID, hybrid ) /* Hybrid architecture */ \ + decl(FAST_BMI2, fast_bmi2 ) /* Native Hardware support for PEXT/PDEP BMI2 instructions */ #define DECLARE_CPU_FEATURE_FLAG(id, name) CPU_##id, CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) @@ -725,6 +726,7 @@ class VM_Version : public Abstract_VM_Version { } static bool compute_has_intel_jcc_erratum(); + static bool compute_fast_bmi2(); static bool os_supports_avx_vectors(); static bool os_supports_apx_egprs(); @@ -912,6 +914,7 @@ class VM_Version : public Abstract_VM_Version { static bool supports_hv() { return _features.supports_feature(CPU_HV); } static bool supports_serialize() { return _features.supports_feature(CPU_SERIALIZE); } static bool supports_hybrid() { return _features.supports_feature(CPU_HYBRID); } + static bool supports_fast_bmi2() { return _features.supports_feature(CPU_FAST_BMI2); } static bool supports_f16c() { return _features.supports_feature(CPU_F16C); } static bool supports_pku() { return _features.supports_feature(CPU_PKU); } static bool supports_ospke() { return _features.supports_feature(CPU_OSPKE); } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 217edb03f122..e88013a50939 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -3220,7 +3220,7 @@ bool Matcher::match_rule_supported(int opcode) { break; case Op_CompressBits: case Op_ExpandBits: - if (!VM_Version::supports_bmi2()) { + if (!VM_Version::supports_fast_bmi2()) { return false; } break; diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java index 01fe54218fe7..fd2b1cdd6af4 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ public class TestBitCompressValueTransform { public final long BOUND2_HI_L = GEN_L.next(); @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public long test1(long value) { return Long.compress(0x8000_0000_0000_0000L, value); } @@ -86,7 +86,7 @@ public void run1() { @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public int test2(int value) { return Integer.compress(0x8000_0000, value); } @@ -98,7 +98,7 @@ public void run2() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "fast_bmi2", "true" }) public int test3(int value) { int filter_bits = value & 0xF; int compress_bits = Integer.compress(15, filter_bits); @@ -118,7 +118,7 @@ public void run3() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "fast_bmi2", "true" }) public long test4(long value) { long filter_bits = value & 0xFL; long compress_bits = Long.compress(15L, filter_bits); @@ -138,7 +138,7 @@ public void run4() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public long test5(long value) { // Since value range includes -1 hence with mask // and value as -1 all the result bits will be set. @@ -156,7 +156,7 @@ public void run5() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public long test6(long value) { // For mask within a strictly -ve value range less than -1, // result of compression will always be a +ve value. @@ -174,7 +174,7 @@ public void run6() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public long test7(long value) { // For mask within a strictly +ve value range, // result of compression will always be a +ve value with @@ -193,7 +193,7 @@ public void run7() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public int test8(int value) { // Since value range includes -1 hence with mask // and value as -1 all the result bits will be set. @@ -211,7 +211,7 @@ public void run8() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public int test9(int value) { // For mask within a strictly -ve value range less than -1, // result of compression will always be a +ve value. @@ -229,7 +229,7 @@ public void run9() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public int test10(int value) { // For mask within a strictly +ve value range, // result of compression will always be a +ve value with @@ -316,7 +316,7 @@ public void run14() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"}) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"fast_bmi2" , "true"}) public int test15(int src, int mask) { // src_type = [min_int + 1, -1] src = Math.max(Integer.MIN_VALUE + 1, Math.min(src, -1)); @@ -363,7 +363,7 @@ public int test16_interpreted(int src, int mask) { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"}) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"fast_bmi2" , "true"}) public int test16(int src, int mask) { src = Math.max(BOUND1_LO_I, Math.min(src, BOUND1_HI_I)); mask = Math.max(BOUND2_LO_I, Math.min(mask, BOUND2_HI_I)); @@ -449,7 +449,7 @@ public int test17_interpreted(int src, int mask) { } @Test - @IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"}) + @IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"fast_bmi2" , "true"}) public int test17(int src, int mask) { src = Math.max(BOUND1_LO_I, Math.min(src, BOUND1_HI_I)); mask = Math.max(BOUND2_LO_I, Math.min(mask, BOUND2_HI_I)); @@ -535,7 +535,7 @@ public long test18_interpreted(long src, long mask) { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"}) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"fast_bmi2" , "true"}) public long test18(long src, long mask) { src = Math.max(BOUND1_LO_L, Math.min(src, BOUND1_HI_L)); mask = Math.max(BOUND2_LO_L, Math.min(mask, BOUND2_HI_L)); @@ -621,7 +621,7 @@ public long test19_interpreted(long src, long mask) { } @Test - @IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"}) + @IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"fast_bmi2" , "true"}) public long test19(long src, long mask) { src = Math.max(BOUND1_LO_L, Math.min(src, BOUND1_HI_L)); mask = Math.max(BOUND2_LO_L, Math.min(mask, BOUND2_HI_L)); @@ -674,7 +674,7 @@ public void run19() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public static long test20(int x) { // Analysis of when this is used to produce wrong results on Windows: // @@ -723,7 +723,7 @@ public void run20() { } @Test - @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" }) + @IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "fast_bmi2", "true" }) public static long test21(long x) { // Analysis of when this is used to produce wrong results on Windows: // diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java b/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java index d2d707d6efbc..4c70014dba33 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestBitShuffleOpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @summary To test various transforms added for bit COMPRESS_BITS and EXPAND_BITS operations * @requires vm.compiler2.enabled * @requires (((os.arch=="x86" | os.arch=="amd64" | os.arch=="x86_64") & - * (vm.cpu.features ~= ".*bmi2.*" & vm.cpu.features ~= ".*bmi1.*" & + * (vm.cpu.features ~= ".*fast_bmi2.*" & vm.cpu.features ~= ".*bmi1.*" & * vm.cpu.features ~= ".*sse2.*")) | * (os.arch=="aarch64" & vm.cpu.features ~= ".*svebitperm.*")) * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java index 9f1687e8cfdf..ed3488303a2a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java @@ -110,6 +110,7 @@ public class ApplicableIRRulesPrinter { "avx512_vbmi2", "avx10_2", "bmi2", + "fast_bmi2", // Intel APX "apx_f", // AArch64 diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index 809953a12636..3541d64aaf55 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ public class CPUInfoTest { "f16c", "pku", "ospke", "cet_ibt", "cet_ss", "avx512_ifma", "serialize", "avx_ifma", "apx_f", "avx10_1", "avx10_2", "avx512_fp16", - "sha512", "hybrid" + "sha512", "hybrid", "fast_bmi2" ); // @formatter:on // Checkstyle: resume From f7a46b725a86e2570f074fc5af4f9937dad4ce37 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Mon, 24 Aug 2026 09:29:16 +0000 Subject: [PATCH 046/223] 8387969: RISC-V: Optimize zero-result integer cmoves with Zicond Co-authored-by: Dingli Zhang Reviewed-by: dzhang, fyang, kwei --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 82 ++++++++++--------- .../cpu/riscv/macroAssembler_riscv.cpp | 73 ++++++++++------- .../cpu/riscv/macroAssembler_riscv.hpp | 3 + 3 files changed, 87 insertions(+), 71 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index b4277f729aee..c0504ba23da7 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2021,47 +2021,49 @@ void C2_MacroAssembler::enc_cmpEqNe_imm0_branch(int cmpFlag, Register op1, Label } void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Register dst, Register src) { - bool is_unsigned = (cmpFlag & unsigned_branch_mask) == unsigned_branch_mask; - int op_select = cmpFlag & (~unsigned_branch_mask); + if (dst != src) { + bool is_unsigned = (cmpFlag & unsigned_branch_mask) == unsigned_branch_mask; + int op_select = cmpFlag & (~unsigned_branch_mask); - switch (op_select) { - case BoolTest::eq: - cmov_eq(op1, op2, dst, src); - break; - case BoolTest::ne: - cmov_ne(op1, op2, dst, src); - break; - case BoolTest::le: - if (is_unsigned) { - cmov_leu(op1, op2, dst, src); - } else { - cmov_le(op1, op2, dst, src); - } - break; - case BoolTest::ge: - if (is_unsigned) { - cmov_geu(op1, op2, dst, src); - } else { - cmov_ge(op1, op2, dst, src); - } - break; - case BoolTest::lt: - if (is_unsigned) { - cmov_ltu(op1, op2, dst, src); - } else { - cmov_lt(op1, op2, dst, src); - } - break; - case BoolTest::gt: - if (is_unsigned) { - cmov_gtu(op1, op2, dst, src); - } else { - cmov_gt(op1, op2, dst, src); - } - break; - default: - assert(false, "unsupported compare condition"); - ShouldNotReachHere(); + switch (op_select) { + case BoolTest::eq: + cmov_eq(op1, op2, dst, src); + break; + case BoolTest::ne: + cmov_ne(op1, op2, dst, src); + break; + case BoolTest::le: + if (is_unsigned) { + cmov_leu(op1, op2, dst, src); + } else { + cmov_le(op1, op2, dst, src); + } + break; + case BoolTest::ge: + if (is_unsigned) { + cmov_geu(op1, op2, dst, src); + } else { + cmov_ge(op1, op2, dst, src); + } + break; + case BoolTest::lt: + if (is_unsigned) { + cmov_ltu(op1, op2, dst, src); + } else { + cmov_lt(op1, op2, dst, src); + } + break; + case BoolTest::gt: + if (is_unsigned) { + cmov_gtu(op1, op2, dst, src); + } else { + cmov_gt(op1, op2, dst, src); + } + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } } } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b245f2650eb0..8be305f2743b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1266,13 +1266,33 @@ void MacroAssembler::wrap_label(Register r1, Register r2, Label &L, #undef INSN -// cmov +// cmov_zicond_eqz: dst = (cond == 0) ? src : dst +void MacroAssembler::cmov_zicond_eqz(Register dst, Register src, Register cond, Register tmp) { + assert(UseZicond, "UseZicond must be enabled"); + assert_different_registers(dst, src, cond); + czero_eqz(dst, dst, cond); + if (src != zr) { + czero_nez(tmp, src, cond); + add(dst, dst, tmp); + } +} + +// cmov_zicond_nez: dst = (cond != 0) ? src : dst +void MacroAssembler::cmov_zicond_nez(Register dst, Register src, Register cond, Register tmp) { + assert(UseZicond, "UseZicond must be enabled"); + assert_different_registers(dst, src, cond); + czero_nez(dst, dst, cond); + if (src != zr) { + czero_eqz(tmp, src, cond); + add(dst, dst, tmp); + } +} + void MacroAssembler::cmov_eq(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { xorr(t0, cmp1, cmp2); - czero_eqz(dst, dst, t0); - czero_nez(t0 , src, t0); - orr(dst, dst, t0); + cmov_zicond_eqz(dst, src, t0, t0); return; } Label no_set; @@ -1282,11 +1302,10 @@ void MacroAssembler::cmov_eq(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_ne(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { xorr(t0, cmp1, cmp2); - czero_nez(dst, dst, t0); - czero_eqz(t0 , src, t0); - orr(dst, dst, t0); + cmov_zicond_nez(dst, src, t0, t0); return; } Label no_set; @@ -1296,11 +1315,10 @@ void MacroAssembler::cmov_ne(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_le(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { slt(t0, cmp2, cmp1); - czero_eqz(dst, dst, t0); - czero_nez(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_eqz(dst, src, t0, t0); return; } Label no_set; @@ -1310,11 +1328,10 @@ void MacroAssembler::cmov_le(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_leu(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { sltu(t0, cmp2, cmp1); - czero_eqz(dst, dst, t0); - czero_nez(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_eqz(dst, src, t0, t0); return; } Label no_set; @@ -1324,11 +1341,10 @@ void MacroAssembler::cmov_leu(Register cmp1, Register cmp2, Register dst, Regist } void MacroAssembler::cmov_ge(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { slt(t0, cmp1, cmp2); - czero_eqz(dst, dst, t0); - czero_nez(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_eqz(dst, src, t0, t0); return; } Label no_set; @@ -1338,11 +1354,10 @@ void MacroAssembler::cmov_ge(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_geu(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { sltu(t0, cmp1, cmp2); - czero_eqz(dst, dst, t0); - czero_nez(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_eqz(dst, src, t0, t0); return; } Label no_set; @@ -1352,11 +1367,10 @@ void MacroAssembler::cmov_geu(Register cmp1, Register cmp2, Register dst, Regist } void MacroAssembler::cmov_lt(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { slt(t0, cmp1, cmp2); - czero_nez(dst, dst, t0); - czero_eqz(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_nez(dst, src, t0, t0); return; } Label no_set; @@ -1366,11 +1380,10 @@ void MacroAssembler::cmov_lt(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_ltu(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { sltu(t0, cmp1, cmp2); - czero_nez(dst, dst, t0); - czero_eqz(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_nez(dst, src, t0, t0); return; } Label no_set; @@ -1380,11 +1393,10 @@ void MacroAssembler::cmov_ltu(Register cmp1, Register cmp2, Register dst, Regist } void MacroAssembler::cmov_gt(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { slt(t0, cmp2, cmp1); - czero_nez(dst, dst, t0); - czero_eqz(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_nez(dst, src, t0, t0); return; } Label no_set; @@ -1394,11 +1406,10 @@ void MacroAssembler::cmov_gt(Register cmp1, Register cmp2, Register dst, Registe } void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Register src) { + assert_different_registers(dst, src); if (UseZicond) { sltu(t0, cmp2, cmp1); - czero_nez(dst, dst, t0); - czero_eqz(t0, src, t0); - orr(dst, dst, t0); + cmov_zicond_nez(dst, src, t0, t0); return; } Label no_set; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index dffb85455f0b..9af9fad06d08 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -685,6 +685,9 @@ class MacroAssembler: public Assembler { void bltz(Register Rs, const address dest); void bgtz(Register Rs, const address dest); + void cmov_zicond_eqz(Register dst, Register src, Register cond, Register tmp = t0); + void cmov_zicond_nez(Register dst, Register src, Register cond, Register tmp = t0); + void cmov_eq(Register cmp1, Register cmp2, Register dst, Register src); void cmov_ne(Register cmp1, Register cmp2, Register dst, Register src); void cmov_le(Register cmp1, Register cmp2, Register dst, Register src); From 661b121b9513b205ace47b9ecfc8d16a32c731f4 Mon Sep 17 00:00:00 2001 From: Lee Jiwon Date: Mon, 24 Aug 2026 09:50:45 +0000 Subject: [PATCH 047/223] 8308183: Add a small ServerSocket based test to verify the fix Reviewed-by: dfuchs --- .../Http1RequestEmptyBufferTest.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 test/jdk/java/net/httpclient/Http1RequestEmptyBufferTest.java diff --git a/test/jdk/java/net/httpclient/Http1RequestEmptyBufferTest.java b/test/jdk/java/net/httpclient/Http1RequestEmptyBufferTest.java new file mode 100644 index 000000000000..abffd8a7d2a7 --- /dev/null +++ b/test/jdk/java/net/httpclient/Http1RequestEmptyBufferTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.Utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @test + * @bug 8308024 + * @summary Verify that the server observes the terminal chunk exactly once + * when the HTTP/1.1 client request body publisher supplies an empty buffer. + * @library /test/lib + * @run junit/othervm ${test.main.class} + */ +public class Http1RequestEmptyBufferTest { + + static final byte[] HEADER_END = new byte[] {'\r', '\n', '\r', '\n'}; + + static byte[] readRequestHeaders(InputStream input) throws IOException { + ByteArrayOutputStream headerBytes = new ByteArrayOutputStream(); + int headerEndMatch = 0, nextByte; + while ((nextByte = input.read()) != -1) { + headerBytes.write(nextByte); + if (nextByte == HEADER_END[headerEndMatch]) { + headerEndMatch++; + if (headerEndMatch == 4) { + return headerBytes.toByteArray(); + } + } else { + headerEndMatch = 0; + } + } + throw new IOException("EOF reached before reaching end of headers"); + } + + static final String TERMINAL_CHUNK = "0\r\n\r\n"; + + static final String RESPONSE_HEADERS = "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "Connection: close\r\n\r\n"; + + static String escape(String value) { + return value.replace("\r", "\\r").replace("\n", "\\n"); + } + + @Test + void test() throws Exception { + try (ServerSocket server = new ServerSocket()) { + server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + String path = "/testChunkEmptyBuffer/"; + URI uri = new URI("http", + null, + server.getInetAddress().getHostAddress(), + server.getLocalPort(), + path, + null, + null); + try (HttpClient client = HttpClient.newBuilder() + .proxy(HttpClient.Builder.NO_PROXY) + .version(HttpClient.Version.HTTP_1_1) + .build()) { + HttpRequest request = HttpRequest.newBuilder(uri) + .PUT(HttpRequest.BodyPublishers.ofByteArrays(List.of(new byte[0]))) + .build(); + CompletableFuture> responseFuture = + client.sendAsync(request, HttpResponse.BodyHandlers.discarding()); + try (Socket connection = server.accept()) { + connection.setSoTimeout((int)Utils.adjustTimeout(1000)); + InputStream input = connection.getInputStream(); + byte[] headerBytes = readRequestHeaders(input); + String headerText = new String(headerBytes, StandardCharsets.US_ASCII) + .toLowerCase(Locale.ROOT); + assertTrue(headerText.contains("transfer-encoding: chunked"), + "Expected Transfer-Encoding: chunked header, got: " + + headerText); + byte[] firstChunkBytes = input.readNBytes(TERMINAL_CHUNK.length()); + OutputStream os = connection.getOutputStream(); + os.write(RESPONSE_HEADERS.getBytes(StandardCharsets.US_ASCII)); + os.flush(); + String requestBody = new String(firstChunkBytes, StandardCharsets.US_ASCII) + + new String(input.readAllBytes(), StandardCharsets.US_ASCII); + assertEquals(escape(TERMINAL_CHUNK), escape(requestBody)); + HttpResponse response = responseFuture.join(); + assertEquals(200, response.statusCode()); + } + } + } + } +} From 01177de13b277bc99add32adfb5816c6a402de33 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 24 Aug 2026 10:54:26 +0000 Subject: [PATCH 048/223] 8390647: Clean up the functions made available in libzip Reviewed-by: lancea, alanb --- src/java.base/share/native/libzip/zip_util.c | 112 ++++++++----------- src/java.base/share/native/libzip/zip_util.h | 29 +---- 2 files changed, 51 insertions(+), 90 deletions(-) diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index 96d3050f5270..0e6e0da91f2f 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -84,10 +84,10 @@ DEF_STATIC_JNI_OnLoad /* * Opens the named file for reading, returning a ZFILE. * - * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c. + * Compare this with winFileHandleOpen in windows/native/libjava/io_util_md.c. * This function does not take JNIEnv* and uses CreateFile (instead of - * CreateFileW). The expectation is that this function will be called only - * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not + * CreateFileW). The expectation is that this function will be called only + * from ZIP_Open, which in turn is used by the JVM, where we do not * need to concern ourselves with wide chars. */ static ZFILE @@ -766,32 +766,6 @@ readCEN(jzfile *zip, jint knownTotal) return cenpos; } -/* - * Opens a zip file with the specified mode. Returns the jzfile object - * or NULL if an error occurred. If a zip error occurred then *pmsg will - * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be - * set to NULL. Caller doesn't need to free the error message. - * The error message, if set, points to a static thread-safe buffer. - */ -jzfile * -ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) -{ - jzfile *zip = NULL; - - /* Clear zip error message */ - if (pmsg != NULL) { - *pmsg = NULL; - } - - zip = ZIP_Get_From_Cache(name, pmsg, lastModified); - - if (zip == NULL && pmsg != NULL && *pmsg == NULL) { - ZFILE zfd = ZFILE_Open(name, mode); - zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified); - } - return zip; -} - /* * Returns the jzfile corresponding to the given file name from the cache of * zip files, or NULL if the file is not in the cache. If the name is longer @@ -799,7 +773,7 @@ ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller * doesn't need to free the error message. */ -jzfile * +static jzfile * ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) { char buf[PATH_MAX]; @@ -827,8 +801,9 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) MLOCK(zfiles_lock); for (zip = zfiles; zip != NULL; zip = zip->next) { if (strcmp(name, zip->name) == 0 - && (zip->lastModified == lastModified || zip->lastModified == 0) - && zip->refs < MAXREFS) { + && (zip->lastModified == lastModified || zip->lastModified == 0) + && zip->refs < MAXREFS) { + zip->refs++; break; } @@ -844,16 +819,8 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller doesn't need to * free the error message. */ - -jzfile * +static jzfile * ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) -{ - return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE); -} - -jzfile * -ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, - jboolean usemmap) { char errbuf[256]; jlong len; @@ -864,7 +831,7 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, } #ifdef USE_MMAP - zip->usemmap = usemmap; + zip->usemmap = JNI_TRUE; #endif zip->refs = 1; zip->lastModified = lastModified; @@ -916,15 +883,28 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, /* * Opens a zip file for reading. Returns the jzfile object or NULL - * if an error occurred. If a zip error occurred then *msg will be - * set to the error message text if msg != 0. Otherwise, *msg will be + * if an error occurred. If a zip error occurred then *pmsg will be + * set to the error message text if pmsg != NULL. Otherwise, *pmsg will be * set to NULL. Caller doesn't need to free the error message. + * The error message, if set, points to a static thread-safe buffer. */ JNIEXPORT jzfile * ZIP_Open(const char *name, char **pmsg) { - jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); - return file; + jzfile *zip = NULL; + + /* Clear zip error message */ + if (pmsg != NULL) { + *pmsg = NULL; + } + const jlong lastModified = 0; + zip = ZIP_Get_From_Cache(name, pmsg, lastModified); + + if (zip == NULL && pmsg != NULL && *pmsg == NULL) { + ZFILE zfd = ZFILE_Open(name, O_RDONLY); + zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified); + } + return zip; } /* @@ -1123,6 +1103,24 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) return ze; } +/* + * Locks the specified zip file for reading. + */ +static void +ZIP_Lock(jzfile *zip) +{ + MLOCK(zip->lock); +} + +/* + * Unlocks the specified zip file. + */ +static void +ZIP_Unlock(jzfile *zip) +{ + MUNLOCK(zip->lock); +} + /* * Free the given jzentry. * In fact we maintain a one-entry cache of the most recently used @@ -1238,30 +1236,12 @@ ZIP_GetNextEntry(jzfile *zip, jint n) return result; } -/* - * Locks the specified zip file for reading. - */ -void -ZIP_Lock(jzfile *zip) -{ - MLOCK(zip->lock); -} - -/* - * Unlocks the specified zip file. - */ -void -ZIP_Unlock(jzfile *zip) -{ - MUNLOCK(zip->lock); -} - /* * Returns the offset of the entry data within the zip file. * Returns -1 if an error occurred, in which case zip->msg will * contain the error text. */ -jlong +static jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry) { /* The Zip file spec explicitly allows the LOC extra data size to @@ -1297,7 +1277,7 @@ ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry) * The current implementation does not support reading an entry that * has the size bigger than 2**32 bytes in ONE invocation. */ -jint +static jint ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len) { jlong entry_size; diff --git a/src/java.base/share/native/libzip/zip_util.h b/src/java.base/share/native/libzip/zip_util.h index 8cfe0b261f5c..d34012f88397 100644 --- a/src/java.base/share/native/libzip/zip_util.h +++ b/src/java.base/share/native/libzip/zip_util.h @@ -145,6 +145,11 @@ #define STORED 0 #define DEFLATED 8 +/* + * Index representing end of hash chain + */ +#define ZIP_ENDCHAIN ((jint) -1) + /* * Support for reading ZIP/JAR files. Some things worth noting: * @@ -236,11 +241,6 @@ typedef struct jzfile { /* Zip file */ jlong locpos; /* position of first LOC header (usually 0) */ } jzfile; -/* - * Index representing end of hash chain - */ -#define ZIP_ENDCHAIN ((jint)-1) - /* * Returns the ZIP entry corresponding to the given (NULL terminated) * entry name. Returns NULL if no entry is found by that name. @@ -260,18 +260,6 @@ ZIP_GetNextEntry(jzfile *zip, jint n); JNIEXPORT jzfile * ZIP_Open(const char *name, char **pmsg); -jzfile * -ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified); - -jzfile * -ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified); - -jzfile * -ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified); - -jzfile * -ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, jboolean usemmap); - JNIEXPORT void ZIP_Close(jzfile *zip); @@ -281,15 +269,8 @@ ZIP_Close(jzfile *zip); */ jzentry * ZIP_GetEntry(jzfile *zip, const char *name); -void -ZIP_Lock(jzfile *zip); -void -ZIP_Unlock(jzfile *zip); -jint -ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); JNIEXPORT void ZIP_FreeEntry(jzfile *zip, jzentry *ze); -jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); JNIEXPORT jboolean ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); From 62a166a0647bdbb7ef41bcc4c042caed3bc7c638 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 24 Aug 2026 12:12:35 +0000 Subject: [PATCH 049/223] 8389452: Inherited @Contended annotation corrupts concrete value class layout Reviewed-by: fparain, jsjolen --- .../share/classfile/classFileParser.cpp | 9 +- .../jdk/internal/vm/annotation/Contended.java | 6 + .../ContendedValueClassInheritanceTest.java | 167 ++++++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 99aef4bb6c76..cd4b32d80465 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2080,7 +2080,7 @@ void MethodAnnotationCollector::apply_to(const methodHandle& m) { void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) { assert(ik != nullptr, "invariant"); - if (has_annotation(_jdk_internal_vm_annotation_Contended)) { + if (ik->is_identity_class() && has_annotation(_jdk_internal_vm_annotation_Contended)) { ik->set_is_contended(is_contended()); } if (has_annotation(_jdk_internal_ValueBased)) { @@ -5676,8 +5676,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, oop_map_blocks->copy(ik->start_of_nonstatic_oop_maps()); } - if (_has_contended_fields || _parsed_annotations->is_contended() || - ( _super_klass != nullptr && _super_klass->has_contended_annotations())) { + if (ik->is_identity_class() && + (_has_contended_fields || _parsed_annotations->is_contended() || + (_super_klass != nullptr && _super_klass->has_contended_annotations()))) { ik->set_has_contended_annotations(true); } @@ -6409,7 +6410,7 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st _layout_info = new FieldLayoutInfo(); FieldLayoutBuilder lb(class_name(), loader_data(), super_klass(), _cp, /*_fields*/ _temp_field_info, - _parsed_annotations->is_contended(), is_inline_type(), + access_flags().is_identity_class() && _parsed_annotations->is_contended(), is_inline_type(), access_flags().is_abstract() && !access_flags().is_identity_class() && !access_flags().is_interface(), _must_be_atomic, _layout_info, _inline_layout_info_array); lb.build_layout(); diff --git a/src/java.base/share/classes/jdk/internal/vm/annotation/Contended.java b/src/java.base/share/classes/jdk/internal/vm/annotation/Contended.java index f32a3ddfa683..90b97d2568af 100644 --- a/src/java.base/share/classes/jdk/internal/vm/annotation/Contended.java +++ b/src/java.base/share/classes/jdk/internal/vm/annotation/Contended.java @@ -67,6 +67,12 @@ * groups. Contention group tags are not inherited, and the same tag used * in a superclass and subclass, represent distinct contention groups. * + *
+ *
+ *

This annotation has no effect when used on or inside value classes. + *

+ *
+ * * @since 1.8 */ @Retention(RetentionPolicy.RUNTIME) diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java new file mode 100644 index 000000000000..4f56b9c75131 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8389452 + * @summary Test that contended annotations are ignored on value class layouts + * @library /test/lib + * @requires vm.flagless + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @compile FieldLayoutAnalyzer.java ContendedValueClassInheritanceTest.java + * @run main runtime.valhalla.inlinetypes.field_layout.ContendedValueClassInheritanceTest + */ + +package runtime.valhalla.inlinetypes.field_layout; + +import jdk.internal.vm.annotation.Contended; +import jdk.test.lib.Asserts; +import jdk.test.lib.process.ProcessTools; + +public class ContendedValueClassInheritanceTest { + private static final int CONTENDED_PADDING_WIDTH = 128; + + static abstract value class Base { + long base = 0; + } + + @Contended + static abstract value class ContendedBase { + long base = 0; + } + + static value class Value extends ContendedBase { + int value = 0; + } + + @Contended + static value class ContendedValue extends Base { + int value = 0; + } + + static class Identity extends ContendedBase { + int value; + } + + @Contended + static class ContendedIdentity extends Base { + int value; + } + + static class TestRunner { + public static void main(String[] args) { + new Value(); + new ContendedValue(); + new Identity(); + new ContendedIdentity(); + } + } + + private static FieldLayoutAnalyzer.ClassLayout getLayout(FieldLayoutAnalyzer fla, Class type) { + String className = type.getName().replace('.', '/'); + FieldLayoutAnalyzer.ClassLayout layout = fla.getClassLayoutFromName(className); + Asserts.assertNotNull(layout, "Missing layout for " + type.getName()); + return layout; + } + + private static int contendedPaddingBlocks(FieldLayoutAnalyzer.ClassLayout layout) { + int count = 0; + for (FieldLayoutAnalyzer.FieldBlock block : layout.nonStaticFields) { + if (block.type() == FieldLayoutAnalyzer.BlockType.PADDING && block.size() == CONTENDED_PADDING_WIDTH) { + count++; + } + } + return count; + } + + private static void assertSameFieldLayout(FieldLayoutAnalyzer.ClassLayout first, + FieldLayoutAnalyzer.ClassLayout second, + String fieldName) { + FieldLayoutAnalyzer.FieldBlock firstField = first.getFieldFromName(fieldName, false); + FieldLayoutAnalyzer.FieldBlock secondField = second.getFieldFromName(fieldName, false); + Asserts.assertEquals(firstField.offset(), secondField.offset(), fieldName + " offset"); + Asserts.assertEquals(firstField.size(), secondField.size(), fieldName + " size"); + Asserts.assertEquals(firstField.alignment(), secondField.alignment(), fieldName + " alignment"); + } + + private static void checkLayouts(FieldLayoutAnalyzer fla) { + // Contended annotations should not affect value base classes. + var base = getLayout(fla, Base.class); + var contendedBase = getLayout(fla, ContendedBase.class); + + Asserts.assertEquals(base.instanceSize, contendedBase.instanceSize); + assertSameFieldLayout(base, contendedBase, "base"); + Asserts.assertEquals(contendedPaddingBlocks(contendedBase), 0); + + // Neither inherited nor declared contended annotations should affect value subclasses. + var value = getLayout(fla, Value.class); + var contendedValue = getLayout(fla, ContendedValue.class); + + Asserts.assertEquals(value.instanceSize, contendedValue.instanceSize); + Asserts.assertEquals(value.payloadSize, contendedValue.payloadSize); + + assertSameFieldLayout(value, contendedValue, "base"); + assertSameFieldLayout(value, contendedValue, "value"); + + Asserts.assertEquals(contendedPaddingBlocks(value), 0); + Asserts.assertEquals(contendedPaddingBlocks(contendedValue), 0); + + // Only the contended identity subclass gets leading and trailing padding. + var identity = getLayout(fla, Identity.class); + var contendedIdentity = getLayout(fla, ContendedIdentity.class); + var identityField = identity.getFieldFromName("value", false); + var contendedIdentityField = contendedIdentity.getFieldFromName("value", false); + + assertSameFieldLayout(identity, contendedIdentity, "base"); + + Asserts.assertEquals(contendedIdentityField.offset(), identityField.offset() + CONTENDED_PADDING_WIDTH); + Asserts.assertEquals(contendedIdentity.instanceSize, identity.instanceSize + 2 * CONTENDED_PADDING_WIDTH); + + Asserts.assertEquals(contendedPaddingBlocks(identity), 0); + Asserts.assertEquals(contendedPaddingBlocks(contendedIdentity), 2); + } + + public static void main(String[] args) throws Exception { + var out = ProcessTools.executeTestJava( + "--enable-preview", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintFieldLayout", + "-XX:-RestrictContended", + "-XX:ContendedPaddingWidth=" + CONTENDED_PADDING_WIDTH, + "-Xshare:off", + "-cp", System.getProperty("java.class.path"), + TestRunner.class.getName()); + out.shouldHaveExitValue(0); + + FieldLayoutAnalyzer.LogOutput log = new FieldLayoutAnalyzer.LogOutput(out.asLines()); + FieldLayoutAnalyzer fla = FieldLayoutAnalyzer.createFieldLayoutAnalyzer(log); + try { + checkLayouts(fla); + fla.check(); + } catch (Throwable t) { + System.out.print(out.getOutput()); + throw t; + } + } +} From 1088f16bb6a48482fc1ea07656e2cd9debd91d2c Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 24 Aug 2026 12:30:04 +0000 Subject: [PATCH 050/223] 8388404: Initialize nm_offset Reviewed-by: coleenp, fparain --- src/hotspot/share/runtime/fieldDescriptor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 17bf5e74e006..aa3bbb76c7f9 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -195,7 +195,7 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj, int indent, int ba bool is_null = false; InlineKlass* vk = InlineKlass::cast(field_holder()->get_inline_type_field_klass(index())); int field_offset = offset() - vk->payload_offset(); - int nm_offset; + int nm_offset = 0; if (!is_null_free_inline_type()) { assert(has_null_marker(), "should have null marker"); @@ -220,6 +220,7 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj, int indent, int ba if (this->field_flags().has_null_marker()) { for (int i = 0; i < indent + 1; i++) st->print(" "); + assert(nm_offset > 0, "must be"); st->print_cr(" - [null_marker] @%d %s", base_offset + nm_offset, is_null ? "Field marked as null" : "Field marked as non-null"); From f5874509cd549ef4ff4df1038b1d736f37175455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Mon, 24 Aug 2026 12:59:23 +0000 Subject: [PATCH 051/223] 8390109: [REDO] Add the hotspot compiler testlibrary to the test-image Reviewed-by: erikj, mchevalier --- make/Main.gmk | 14 +++- .../hotspot/test/BuildCompilerTestlibrary.gmk | 76 +++++++++++++++++++ .../test/ApplicableIRRulesPrinter.java | 1 + 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 make/hotspot/test/BuildCompilerTestlibrary.gmk diff --git a/make/Main.gmk b/make/Main.gmk index a78fc509ff98..1c3ee71f3028 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -751,6 +751,18 @@ $(eval $(call SetupTarget, test-image-lib, \ DEPS := build-test-lib, \ )) +$(eval $(call SetupTarget, build-hotspot-compiler-testlibrary, \ + MAKEFILE := hotspot/test/BuildCompilerTestlibrary, \ + TARGET := build-hotspot-compiler-testlibrary, \ + DEPS := exploded-image build-test-lib, \ +)) + +$(eval $(call SetupTarget, test-image-hotspot-compiler-testlibrary, \ + MAKEFILE := hotspot/test/BuildCompilerTestlibrary, \ + TARGET := test-image-hotspot-compiler-testlibrary, \ + DEPS := build-hotspot-compiler-testlibrary, \ +)) + $(eval $(call SetupTarget, build-test-setup-aot, \ MAKEFILE := test/BuildTestSetupAOT, \ DEPS := interim-langtools exploded-image, \ @@ -1303,7 +1315,7 @@ all-docs-bundles: docs-jdk-bundles docs-javase-bundles docs-reference-bundles test-image: prepare-test-image test-image-jdk-jtreg-native \ test-image-demos-jdk test-image-libtest-jtreg-native \ test-image-lib test-image-lib-native \ - test-image-setup-aot + test-image-setup-aot test-image-hotspot-compiler-testlibrary ifneq ($(JVM_TEST_IMAGE_TARGETS), ) # If JVM_TEST_IMAGE_TARGETS is externally defined, use it instead of the diff --git a/make/hotspot/test/BuildCompilerTestlibrary.gmk b/make/hotspot/test/BuildCompilerTestlibrary.gmk new file mode 100644 index 000000000000..0da107229fa9 --- /dev/null +++ b/make/hotspot/test/BuildCompilerTestlibrary.gmk @@ -0,0 +1,76 @@ +# +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include MakeFileStart.gmk + +################################################################################ +# This file builds the Hotspot compiler testlibrary. +################################################################################ + +include CopyFiles.gmk +include JavaCompilation.gmk + +############################################################################### + +COMPILER_TESTLIBRARY_BASEDIR := $(TOPDIR)/test/hotspot/jtreg/compiler/lib +COMPILER_TESTLIBRARY_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/compiler-testlibrary +COMPILER_TESTLIBRARY_JAR := $(COMPILER_TESTLIBRARY_SUPPORT)/compiler-testlibrary.jar +TEST_LIB_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/lib +WB_CP := $(TEST_LIB_SUPPORT)/wb_classes +TEST_LIB_CP := $(TEST_LIB_SUPPORT)/test-lib_classes + +$(eval $(call SetupJavaCompilation, BUILD_COMPILER_TESTLIBRARY, \ + TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ + SRC := $(COMPILER_TESTLIBRARY_BASEDIR), \ + BIN := $(COMPILER_TESTLIBRARY_SUPPORT)/classes, \ + JAR := $(COMPILER_TESTLIBRARY_JAR), \ + JAVAC_FLAGS := -cp $(WB_CP) \ + -cp $(TEST_LIB_CP) \ + --add-exports java.base/jdk.internal.math=ALL-UNNAMED, \ +)) + +TARGETS += $(BUILD_COMPILER_TESTLIBRARY) + +build-hotspot-compiler-testlibrary: $(TARGETS) + +################################################################################ +# Targets for building test-image. +################################################################################ + +# Copy to hotspot jtreg test image +$(eval $(call SetupCopyFiles, COPY_COMPILER_TESTLIBRARY, \ + DEST := $(TEST_IMAGE_DIR)/compiler-testlibrary, \ + FILES := $(COMPILER_TESTLIBRARY_JAR), \ +)) + +IMAGE_TARGETS += $(COPY_COMPILER_TESTLIBRARY) + +test-image-hotspot-compiler-testlibrary: $(IMAGE_TARGETS) + +.PHONY: build-hotspot-compiler-testlibrary test-image-hotspot-compiler-testlibrary + +################################################################################ + +include MakeFileEnd.gmk diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java index ed3488303a2a..59115c891157 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java @@ -442,6 +442,7 @@ private boolean hasNoRequiredFlags(String[] orRules, String ruleType) { return returnValue; } + @SuppressWarnings("preview") private boolean check(String flag, String value) { if (flag.isEmpty()) { TestFormat.failNoThrow("Provided empty flag" + failAt()); From dcd4a6109928f7d7adebcc552a810807e91c36aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 24 Aug 2026 13:47:57 +0000 Subject: [PATCH 052/223] 8389140: VarHandle CAS should not initialize value class Reviewed-by: liach, jpai, dholmes --- src/hotspot/share/prims/unsafe.cpp | 1 - .../FlatArrayDoesNotInitialize.java | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index cb5987045754..6bdcc1267eda 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -346,7 +346,6 @@ UNSAFE_ENTRY(jint, Unsafe_FieldLayout(JNIEnv *env, jobject unsafe, jobject field UNSAFE_ENTRY(jarray, Unsafe_NewSpecialArray(JNIEnv *env, jobject unsafe, jclass elmClass, jint len, jint layoutKind)) { oop mirror = JNIHandles::resolve_non_null(elmClass); Klass* klass = java_lang_Class::as_Klass(mirror); - klass->initialize(CHECK_NULL); if (len < 0) { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Array length is negative"); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java new file mode 100644 index 000000000000..50138c433b54 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @summary Test that creating an array of T does not initialize class T + * @enablePreview + * @compile FlatArrayDoesNotInitialize.java + * @run main/othervm runtime.valhalla.inlinetypes.FlatArrayDoesNotInitialize + */ +package runtime.valhalla.inlinetypes; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + + +public class FlatArrayDoesNotInitialize { + static boolean initialized; + + static value class MyValue { + static { + initialized = true; + } + } + + public static void main(String[] args) { + MyValue[] array = new MyValue[1]; + VarHandle handle = MethodHandles.arrayElementVarHandle(MyValue[].class); + if (initialized) { + throw new AssertionError("Should not be initialized"); + } + if (!(boolean) handle.compareAndSet(array, 0, null, null)) { + throw new AssertionError("CAS failed"); + } + if (initialized) { + throw new AssertionError("Should not be initialized"); + } + } +} + From fd943b7b1032f022fa3f5b2db30b6559e4a825fe Mon Sep 17 00:00:00 2001 From: Ivan Bereziuk Date: Mon, 24 Aug 2026 14:45:22 +0000 Subject: [PATCH 053/223] 8390824: ProblemList container tests intolerant of non-writable /tmp Reviewed-by: cnorrbin, rsunderbabu --- test/hotspot/jtreg/ProblemList.txt | 2 ++ test/jdk/ProblemList.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 059e2b3e083f..a4308c7ea301 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -112,6 +112,8 @@ runtime/Thread/TestAlwaysPreTouchStacks.java 8383372 macosx-aarch64 applications/jcstress/copy.java 8229852 linux-all containers/docker/TestJFREvents.java 8327723 linux-x64 +containers/docker/TestLimitsUpdating.java 8390823 linux-all +containers/docker/ShareTmpDir.java 8390823 linux-all ############################################################################# diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 16d23f73b38d..86cdbc4c8258 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -624,6 +624,8 @@ jdk/jfr/event/oldobject/TestZ.java 8375615 generic- # jdk_internal +jdk/internal/platform/docker/TestLimitsUpdating.java 8390823 linux-all + ############################################################################ # jdk_jpackage From 60c4ae62ff895c5bdf0a884ee6e4b263d8db2950 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 24 Aug 2026 15:15:42 +0000 Subject: [PATCH 054/223] 8390914: [leyden] add missing relocations for addresses recorded in AOT code cache Reviewed-by: fyang, adinn, dzhang --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 8 ++-- .../cpu/aarch64/stubGenerator_aarch64.cpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 4 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 45 ++++++++++--------- src/hotspot/share/code/aotCodeCache.cpp | 4 +- 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 78f8a86dcf34..6d280d9e8ab9 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1972,7 +1972,9 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, mov(r1, r_sub_klass); // r1 <- r4 mov(r2, /*expected*/rscratch1); // r2 <- r8 mov(r3, result); // r3 <- r5 - mov(r4, (address)("mismatch")); // r4 <- const + const char* msg = "mismatch"; + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + lea(r4, ExternalAddress((address)str)); // r4 <- const rt_call(CAST_FROM_FN_PTR(address, Klass::on_secondary_supers_verification_failure), rscratch2); should_not_reach_here(); } @@ -2043,7 +2045,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, stp(rscratch2, lr, Address(pre(sp, -2 * wordSize))); mov(r0, reg); - movptr(rscratch1, (uintptr_t)(address)b); + lea(rscratch1, ExternalAddress((address)b)); // call indirectly to solve generation ordering problem lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -2094,7 +2096,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f } else { ldr(r0, addr); } - movptr(rscratch1, (uintptr_t)(address)b); + lea(rscratch1, ExternalAddress((address)b)); // call indirectly to solve generation ordering problem lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 61e6e48db73e..ca78fc0952f2 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -827,7 +827,7 @@ class StubGenerator: public StubCodeGenerator { assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); #endif BLOCK_COMMENT("call MacroAssembler::debug"); - __ mov(rscratch1, CAST_FROM_FN_PTR(address, MacroAssembler::debug64)); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); __ blr(rscratch1); __ hlt(0); @@ -12826,7 +12826,7 @@ class StubGenerator: public StubCodeGenerator { // Native caller has no idea how to handle exceptions, // so we just crash here. Up to callee to catch exceptions. __ verify_oop(r0); - __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception))); __ blr(rscratch1); __ should_not_reach_here(); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 8be305f2743b..ec044b6f824d 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5375,7 +5375,9 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, mv(x11, r_sub_klass); mv(x12, tmp3); mv(x13, result); - mv(x14, (address)("mismatch")); + const char* msg = "mismatch"; + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + la(x14, ExternalAddress((address) str)); rt_call(CAST_FROM_FN_PTR(address, Klass::on_secondary_supers_verification_failure)); should_not_reach_here(); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index d5b39f8b0eb8..dd6a6ed51ed4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4607,7 +4607,7 @@ void MacroAssembler::lookup_secondary_supers_table_var(Register r_sub_klass, assert(Array::length_offset_in_bytes() == 0, "Adjust this code"); cmpq(r_super_klass, Address(r_array_base, r_array_index, Address::times_8)); - jccb(Assembler::equal, L_success); + jcc(Assembler::equal, L_success); // Restore slot to its true value movb(slot, Address(r_super_klass, Klass::hash_slot_offset())); @@ -4618,7 +4618,7 @@ void MacroAssembler::lookup_secondary_supers_table_var(Register r_sub_klass, // Is there another entry to check? Consult the bitmap. btq(r_bitmap, 1); - jccb(Assembler::carryClear, L_failure); + jcc(Assembler::carryClear, L_failure); // Calls into the stub generated by lookup_secondary_supers_table_slow_path. // Arguments: r_super_klass, r_array_base, r_array_index, r_bitmap. @@ -4757,21 +4757,6 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl } } -struct VerifyHelperArguments { - Klass* _super; - Klass* _sub; - intptr_t _linear_result; - intptr_t _table_result; -}; - -static void verify_secondary_supers_table_helper(const char* msg, VerifyHelperArguments* args) { - Klass::on_secondary_supers_verification_failure(args->_super, - args->_sub, - args->_linear_result, - args->_table_result, - msg); -} - // Make sure that the hashed lookup and a linear scan agree. void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, Register r_super_klass, @@ -4814,15 +4799,31 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, cmpl(linear_result, result); jcc(Assembler::equal, L_done); - { // To avoid calling convention issues, build a record on the stack - // and pass the pointer to that instead. + { // Push values on stack and load them into argument registers + // to avoid overlaping registers issue. push(result); push(linear_result); push(r_sub_klass); push(r_super_klass); - movptr(c_rarg1, rsp); - movptr(c_rarg0, (uintptr_t) "mismatch"); - call(RuntimeAddress(CAST_FROM_FN_PTR(address, verify_secondary_supers_table_helper))); + movptr(c_rarg0, Address(rsp, 0 * wordSize)); // super + movptr(c_rarg1, Address(rsp, 1 * wordSize)); // sub + movptr(c_rarg2, Address(rsp, 2 * wordSize)); // linear_result + movptr(c_rarg3, Address(rsp, 3 * wordSize)); // table_result + const char* msg = "mismatch"; + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + lea(rscratch1, ExternalAddress((address)str)); +#ifdef _WIN64 + // Win64 pass only 4 arguments in registers, push message on stack. + // Windows always allocates space for its register args and we + // need one more for 5th argument. + subq(rsp, (frame::arg_reg_save_area_bytes + wordSize)); + andq(rsp, -StackAlignmentInBytes); // align stack as required by ABI + movptr(Address(rsp, frame::arg_reg_save_area_bytes), rscratch1); +#else + movptr(c_rarg4, rscratch1); + andq(rsp, -StackAlignmentInBytes); // align stack as required by ABI +#endif + call(RuntimeAddress(CAST_FROM_FN_PTR(address, Klass::on_secondary_supers_verification_failure))); should_not_reach_here(); } bind(L_done); diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index c29f5726236b..d51b5ca68d1f 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -39,6 +39,7 @@ #include "gc/shared/gcConfig.hpp" #include "logging/logStream.hpp" #include "memory/memoryReserver.hpp" +#include "oops/klass.hpp" #include "prims/jvmtiThreadState.hpp" #include "prims/upcallLinker.hpp" #include "runtime/deoptimization.hpp" @@ -2098,10 +2099,11 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_final_transition_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_transition_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_end_transition_C); - // already added for #if defined(AARCH64) && ! defined(PRODUCT) ADD_EXTERNAL_ADDRESS(JavaThread::verify_cross_modify_fence_failure); #endif // AARCH64 && !PRODUCT + // Used by lookup_secondary_supers_table + ADD_EXTERNAL_ADDRESS(Klass::on_secondary_supers_verification_failure); } #endif // COMPILER2 From 8158dfe343c32a93374a51b584a26100e24de16a Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 24 Aug 2026 15:57:51 +0000 Subject: [PATCH 055/223] 8390550: C2 hit MemLimit when run with -Xcomp -XX:VerifyIterativeGVN=1110 Co-authored-by: Christian Hagedorn Reviewed-by: chagedorn, dlong --- src/hotspot/share/opto/c2_globals.hpp | 5 + src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/macro.cpp | 118 +++++++++++------- .../macronodes/TestMacroExpansion.java | 114 +++++++++++++++++ .../TestMacroExpansionCleanupCount.java | 47 +++++++ 5 files changed, 243 insertions(+), 43 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/macronodes/TestMacroExpansion.java create mode 100644 test/hotspot/jtreg/compiler/macronodes/TestMacroExpansionCleanupCount.java diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 2de571e324a3..33799f25d4f4 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -726,6 +726,11 @@ "Re-process nodes that could benefit from a deep revisit after " \ "the IGVN worklist drains") \ \ + product(uint, MacroExpansionCleanupCount, 16, DIAGNOSTIC, \ + "Run IGVN to clean the graph after this many macro nodes are " \ + "expanded or when we approach the max live node limit.") \ + range(1, 100) \ + \ develop(uint, VerifyIterativeGVN, 0, \ "Verify Iterative Global Value Numbering =FEDCBA, with:" \ " F: verify IGVN method return invariants" \ diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index dc457ca4b3b4..fbecaba01a50 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3322,7 +3322,7 @@ void Compile::Optimize() { return; } print_method(PHASE_AFTER_MACRO_ELIMINATION, 2); - if (mex.expand_macro_nodes()) { + if (!mex.expand_macro_nodes()) { assert(failing(), "must bail out w/ explicit message"); return; } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index b5329c861769..ccf2cb0382ff 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -3199,6 +3199,17 @@ void PhaseMacroExpand::refine_strip_mined_loop_macro_nodes() { } } +// Clean up the graph so we're less likely to hit the maximum node limit +static bool cleanup_graph(PhaseIterGVN& igvn) { + igvn.set_delay_transform(false); + igvn.optimize(); + if (igvn.C->failing()) { + return false; + } + igvn.set_delay_transform(true); + return true; +} + //---------------------------eliminate_macro_nodes---------------------- // Eliminate scalar replaced allocations and associated locks. void PhaseMacroExpand::eliminate_macro_nodes(bool eliminate_locks) { @@ -3312,12 +3323,9 @@ void PhaseMacroExpand::eliminate_macro_nodes(bool eliminate_locks) { // other macro nodes can remove all these safepoints, allowing the allocation to be removed. // Hence after igvn we retry removing macro nodes if some progress that has been made in this // iteration. - _igvn.set_delay_transform(false); - _igvn.optimize(); - if (C->failing()) { - return; + if (!cleanup_graph(_igvn)) { + return; // failing } - _igvn.set_delay_transform(true); if (!progress) { break; @@ -3407,21 +3415,18 @@ void PhaseMacroExpand::eliminate_opaque_looplimit_macro_nodes() { } //------------------------------expand_macro_nodes---------------------- -// Returns true if a failure occurred. +// Returns false if a failure occurred. bool PhaseMacroExpand::expand_macro_nodes() { if (StressMacroExpansion) { C->shuffle_macro_nodes(); } - // Clean up the graph so we're less likely to hit the maximum node - // limit - _igvn.set_delay_transform(false); - _igvn.optimize(); - if (C->failing()) return true; - _igvn.set_delay_transform(true); - + // Clean up after eliminate_opaque_looplimit_macro_nodes() + if (!cleanup_graph(_igvn)) { + return false; // failing + } - // Because we run IGVN after each expansion, some macro nodes may go + // Because we run IGVN after set of expansions, some macro nodes may go // dead and be removed from the list as we iterate over it. Move // Allocate nodes (processed in a second pass) at the beginning of // the list and then iterate from the last element of the list until @@ -3429,26 +3434,34 @@ bool PhaseMacroExpand::expand_macro_nodes() { // the list due to nodes going dead. C->sort_macro_nodes(); - // expand arraycopy "macro" nodes first // For ReduceBulkZeroing, we must first process all arraycopy nodes - // before the allocate nodes are expanded. + // before the allocate nodes are expanded. Sorting macro nodes list + // enforces it. + + // Worst case is a macro node gets expanded into about 200 nodes. + // Allow 50% more for optimization. + static const uint macro_expansion_estimate = 300; + const uint macro_expansion_margin = macro_expansion_estimate * MacroExpansionCleanupCount; + const uint macro_expansion_limit = C->max_node_limit() > macro_expansion_margin ? + C->max_node_limit() - macro_expansion_margin : 0; + uint pending_expansions_to_cleanup = 0; + while (C->macro_count() > 0) { int macro_count = C->macro_count(); - Node * n = C->macro_node(macro_count-1); + Node* n = C->macro_node(macro_count-1); assert(n->is_macro(), "only macro nodes expected here"); if (_igvn.type(n) == Type::TOP || (n->in(0) != nullptr && n->in(0)->is_top())) { // node is unreachable, so don't try to expand it C->remove_macro_node(n); continue; } + // Reached Allocate nodes - jump to second pass to process them. if (n->is_Allocate()) { break; } // Make sure expansion will not cause node limit to be exceeded. - // Worst case is a macro node gets expanded into about 200 nodes. - // Allow 50% more for optimization. - if (C->check_node_count(300, "out of nodes before macro expansion")) { - return true; + if (C->check_node_count(macro_expansion_estimate, "out of nodes before macro expansion")) { + return false; } DEBUG_ONLY(int old_macro_count = C->macro_count();) @@ -3488,22 +3501,35 @@ bool PhaseMacroExpand::expand_macro_nodes() { } } assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); - if (C->failing()) return true; + if (C->failing()) { + return false; + } C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n); - // Clean up the graph so we're less likely to hit the maximum node - // limit - _igvn.set_delay_transform(false); - _igvn.optimize(); - if (C->failing()) return true; - _igvn.set_delay_transform(true); + pending_expansions_to_cleanup++; + if (pending_expansions_to_cleanup < MacroExpansionCleanupCount && + C->live_nodes() < macro_expansion_limit) { + // skip clean up + continue; + } + if (!cleanup_graph(_igvn)) { + return false; // failing + } + pending_expansions_to_cleanup = 0; + } + + // Cleanup graph before expanding Allocate nodes. + if (pending_expansions_to_cleanup > 0) { + if (!cleanup_graph(_igvn)) { + return false; // failing + } + pending_expansions_to_cleanup = 0; } // All nodes except Allocate nodes are expanded now. There could be // new optimization opportunities (such as folding newly created // load from a just allocated object). Run IGVN. - // expand "macro" nodes // nodes are removed from the macro list as they are processed while (C->macro_count() > 0) { int macro_count = C->macro_count(); @@ -3515,10 +3541,8 @@ bool PhaseMacroExpand::expand_macro_nodes() { continue; } // Make sure expansion will not cause node limit to be exceeded. - // Worst case is a macro node gets expanded into about 200 nodes. - // Allow 50% more for optimization. - if (C->check_node_count(300, "out of nodes before macro expansion")) { - return true; + if (C->check_node_count(macro_expansion_estimate, "out of nodes before macro expansion")) { + return false; } switch (n->class_id()) { case Node::Class_Allocate: @@ -3531,19 +3555,29 @@ bool PhaseMacroExpand::expand_macro_nodes() { assert(false, "unknown node type in macro list"); } assert(C->macro_count() < macro_count, "must have deleted a node from macro list"); - if (C->failing()) return true; + if (C->failing()) { + return false; + } C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n); - // Clean up the graph so we're less likely to hit the maximum node - // limit - _igvn.set_delay_transform(false); - _igvn.optimize(); - if (C->failing()) return true; - _igvn.set_delay_transform(true); + pending_expansions_to_cleanup++; + if (pending_expansions_to_cleanup < MacroExpansionCleanupCount && + C->live_nodes() < macro_expansion_limit) { + // skip clean up + continue; + } + if (!cleanup_graph(_igvn)) { + return false; // failing + } + pending_expansions_to_cleanup = 0; + } + if (pending_expansions_to_cleanup > 0) { + if (!cleanup_graph(_igvn)) { + return false; // failing + } } - _igvn.set_delay_transform(false); - return false; + return true; } #ifndef PRODUCT diff --git a/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansion.java b/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansion.java new file mode 100644 index 000000000000..d47cd787ebb1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansion.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8390550 + * @key stress + * @requires vm.compiler2.enabled + * @summary Test scalarized calls and entry points around calling convention limits. + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package compiler.macronodes; + +import compiler.lib.compile_framework.CompileFramework; +import compiler.lib.template_framework.Template; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import static compiler.lib.template_framework.Template.*; + +public class TestMacroExpansion { + private static final String GENERATED_CLASS_NAME = "GeneratedTest"; + private static final String PACKAGE_NAME = "compiler.macronodes"; + private static final String QUALIFIED_NAME = PACKAGE_NAME + "." + GENERATED_CLASS_NAME; + + public static void main(String[] args) throws Exception { + CompileFramework compileFramework = new CompileFramework(); + compileFramework.addJavaSourceCode(GENERATED_CLASS_NAME, generate()); + compileFramework.compile(); + String[] command = { + "-classpath", + compileFramework.getEscapedClassPathOfCompiledClasses(), + "-Xcomp", + "-XX:-TieredCompilation", + "-XX:CompileCommand=compileonly," + QUALIFIED_NAME + "::test", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:VerifyIterativeGVN=1110", + QUALIFIED_NAME + }; + + OutputAnalyzer analyzer = ProcessTools.executeTestJava(command); + analyzer.shouldHaveExitValue(0); + } + + static String generate() { + final int rows = 140; + final int args = 9; + return Template.make(() -> scope( + let("className", GENERATED_CLASS_NAME), + let("packageName", PACKAGE_NAME), + """ + package #packageName; + + public class #className { + interface I { + } + + public static void main(String[] args) { + test(); + } + + static class A implements I { + } + + static A a = new A(); + + static Object[] arr; + + """, + " static void init(", repeatAndJoin(args, ", ", i -> scope("I i" + i)), ") {\n", + " arr = new Object[] {", repeatAndJoin(args, ", ", i -> scope("i" + i)), "};\n", + """ + } + + """, + repeatAndJoin(rows, "\n", rowIndex -> scope( + " static Object ", repeatAndJoin(args, ", ", index -> scope( "o" + (index + rowIndex * args))), ";" + )), "\n", + """ + + static void test() { + """, + repeatAndJoin(rows, "\n", rowIndex -> scope( + " init(", repeatAndJoin(args, ", ", index -> scope( "(I)o" + (index + rowIndex * args))), ");" + )), "\n", + """ + } + } + """ + )).render(); + } +} diff --git a/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansionCleanupCount.java b/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansionCleanupCount.java new file mode 100644 index 000000000000..29febbdfa312 --- /dev/null +++ b/test/hotspot/jtreg/compiler/macronodes/TestMacroExpansionCleanupCount.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=min + * @bug 8390550 + * @requires vm.compiler2.enabled + * @summary Test MacroExpansionCleanupCount flag minimum value + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:MacroExpansionCleanupCount=1 ${test.main.class} + */ + +/* + * @test id=max + * @bug 8390550 + * @requires vm.compiler2.enabled + * @summary Test MacroExpansionCleanupCount flag maximum value + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:MacroExpansionCleanupCount=100 ${test.main.class} + */ + +package compiler.macronodes; + +public class TestMacroExpansionCleanupCount { + + public static void main(String[] args) throws Exception { + System.out.println("Test passed"); + } +} From 372ce0802e8f88ed789bf37f2bb423453f4cf7d3 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 24 Aug 2026 16:40:26 +0000 Subject: [PATCH 056/223] 8390917: NullPointerException test fails with new message Reviewed-by: jsjolen, fparain --- .../NullPointerExceptionTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java index 399cda958db0..01b74a1365dd 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java @@ -111,8 +111,15 @@ public static void checkMessage(Throwable t, String expression, } if (obtainedMsg != expectedMsg && // E.g. both are null. !obtainedMsg.equals(expectedMsg)) { - System.out.println("expected msg: " + expectedMsg); - Asserts.assertEquals(expectedMsg, obtainedMsg); + try { + System.out.println("expected msg: " + expectedMsg); + Asserts.assertEquals(expectedMsg, obtainedMsg); + } catch (RuntimeException rte) { + // Due to lack of information about null restricted fields in Xcomp, we may also guess + // that that was the reason for the NPE. + Asserts.assertTrue(obtainedMsg.contains(expectedMsg) && + obtainedMsg.contains("is a null restricted field and there's an attempt to store null in it")); + } } System.out.println("\n----"); } From 0cec602c8a5fe175a7d19a1729b7052a8ee27fd5 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 24 Aug 2026 16:59:26 +0000 Subject: [PATCH 057/223] 8366417: Use InstanceKlass instead of Klass in jfieldIDWorkaround Reviewed-by: jsjolen, iklam --- src/hotspot/share/prims/jni.cpp | 55 ++++++++++--------- .../share/runtime/jfieldIDWorkaround.hpp | 4 +- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index fa61bd74cb8f..f989c6b25672 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -203,14 +203,14 @@ bool jfieldIDWorkaround::is_valid_jfieldID(Klass* k, jfieldID id) { } -intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, int offset) { +intptr_t jfieldIDWorkaround::encode_klass_hash(InstanceKlass* k, int offset) { if (offset <= small_offset_mask) { - Klass* field_klass = k; - Klass* super_klass = field_klass->super(); + InstanceKlass* field_klass = k; + InstanceKlass* super_klass = field_klass->super(); // With compressed oops the most super class with nonstatic fields would // be the owner of fields embedded in the header. - while (InstanceKlass::cast(super_klass)->has_nonstatic_fields() && - InstanceKlass::cast(super_klass)->contains_field_offset(offset)) { + while (super_klass->has_nonstatic_fields() && + super_klass->contains_field_offset(offset)) { field_klass = super_klass; // super contains the field also super_klass = field_klass->super(); } @@ -376,12 +376,13 @@ JNI_ENTRY(jmethodID, jni_FromReflectedMethod(JNIEnv *env, jobject method)) mirror = java_lang_reflect_Method::clazz(reflected); slot = java_lang_reflect_Method::slot(reflected); } - Klass* k1 = java_lang_Class::as_Klass(mirror); + // The mirror is always an InstanceKlass. + InstanceKlass* k1 = java_lang_Class::as_InstanceKlass(mirror); // Make sure class is initialized before handing id's out to methods k1->initialize(CHECK_NULL); - Method* m = InstanceKlass::cast(k1)->method_with_idnum(slot); - ret = m==nullptr? nullptr : m->jmethod_id(); // return null if reflected method deleted + Method* m = k1->method_with_idnum(slot); + ret = m == nullptr? nullptr : m->jmethod_id(); // return null if reflected method deleted return ret; JNI_END @@ -397,7 +398,8 @@ JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field)) // field is a handle to a java.lang.reflect.Field object oop reflected = JNIHandles::resolve_non_null(field); oop mirror = java_lang_reflect_Field::clazz(reflected); - Klass* k1 = java_lang_Class::as_Klass(mirror); + // The klass for the field is initialized as an InstanceKlass. + InstanceKlass* k1 = java_lang_Class::as_InstanceKlass(mirror); int slot = java_lang_reflect_Field::slot(reflected); int modifiers = java_lang_reflect_Field::modifiers(reflected); @@ -406,8 +408,8 @@ JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field)) // First check if this is a static field if (modifiers & JVM_ACC_STATIC) { - int offset = InstanceKlass::cast(k1)->field_offset( slot ); - JNIid* id = InstanceKlass::cast(k1)->jni_id_for(offset); + int offset = k1->field_offset( slot ); + JNIid* id = k1->jni_id_for(offset); assert(id != nullptr, "corrupt Field object"); DEBUG_ONLY(id->set_is_static_field_id();) // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* @@ -418,9 +420,9 @@ JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field)) // The slot is the index of the field description in the field-array // The jfieldID is the offset of the field within the object // It may also have hash bits for k, if VerifyJNIFields is turned on. - int offset = InstanceKlass::cast(k1)->field_offset( slot ); - bool is_flat = InstanceKlass::cast(k1)->field_is_flat(slot); - assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object"); + int offset = k1->field_offset( slot ); + bool is_flat = k1->field_is_flat(slot); + assert(k1->contains_field_offset(offset), "stay within object"); ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset, is_flat); return ret; JNI_END @@ -1762,17 +1764,19 @@ JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, // Make sure class is initialized before handing id's out to fields k->initialize(CHECK_NULL); - fieldDescriptor fd; - if (!k->is_instance_klass() || - !InstanceKlass::cast(k)->find_field(fieldname, signame, false, &fd)) { - ResourceMark rm; - THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + fieldDescriptor fd; + if (ik->find_field(fieldname, signame, false, &fd)) { + // A jfieldID for a non-static field is simply the offset of the field within the instanceOop + // It may also have hash bits for k, if VerifyJNIFields is turned on. + return jfieldIDWorkaround::to_instance_jfieldID(ik, fd.offset(), fd.is_flat()); + } } - // A jfieldID for a non-static field is simply the offset of the field within the instanceOop - // It may also have hash bits for k, if VerifyJNIFields is turned on. - ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset(), fd.is_flat()); - return ret; + // Not an InstanceKlass or the field wasn't found. + ResourceMark rm; + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); JNI_END @@ -1998,7 +2002,8 @@ JNI_ENTRY(jobject, jni_ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldI fieldDescriptor fd; bool found = false; - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); + // The klass for the field is initialized as an InstanceKlass. + InstanceKlass* k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(cls)); assert(jfieldIDWorkaround::is_static_jfieldID(fieldID) == (isStatic != 0), "invalid fieldID"); @@ -2010,7 +2015,7 @@ JNI_ENTRY(jobject, jni_ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldI } else { // Non-static field. The fieldID is really the offset of the field within the instanceOop. int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); - found = InstanceKlass::cast(k)->find_field_from_offset(offset, false, &fd); + found = k->find_field_from_offset(offset, false, &fd); } assert(found, "bad fieldID passed into jni_ToReflectedField"); oop reflected = Reflection::new_field(&fd, CHECK_NULL); diff --git a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp index 44f109b3c35c..9919b85183a8 100644 --- a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp +++ b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp @@ -101,7 +101,7 @@ class jfieldIDWorkaround: AllStatic { // the jfieldID is created with. return checked_cast(result); } - static intptr_t encode_klass_hash(Klass* k, int offset); + static intptr_t encode_klass_hash(InstanceKlass* k, int offset); static bool klass_hash_ok(Klass* k, jfieldID id); static void verify_instance_jfieldID(Klass* k, jfieldID id); @@ -122,7 +122,7 @@ class jfieldIDWorkaround: AllStatic { return ((as_uint & flat_mask_in_place) != 0); } - static jfieldID to_instance_jfieldID(Klass* k, int offset, bool is_flat) { + static jfieldID to_instance_jfieldID(InstanceKlass* k, int offset, bool is_flat) { intptr_t as_uint = ((offset & large_offset_mask) << offset_shift) | instance_mask_in_place; if (is_flat) { From 3cc0be653ba4c9bd4590a73812ee64c18b2f791b Mon Sep 17 00:00:00 2001 From: Dean Long Date: Mon, 24 Aug 2026 20:22:39 +0000 Subject: [PATCH 058/223] 8390603: Remove obsolete thread transition states Reviewed-by: dholmes, fbredberg, pchilanomate --- .../cpu/aarch64/downcallLinker_aarch64.cpp | 2 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 9 +------- .../templateInterpreterGenerator_aarch64.cpp | 2 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 4 ++-- .../arm/templateInterpreterGenerator_arm.cpp | 2 +- src/hotspot/cpu/ppc/downcallLinker_ppc.cpp | 2 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 21 ++++------------- .../ppc/templateInterpreterGenerator_ppc.cpp | 20 ++++------------ .../cpu/riscv/downcallLinker_riscv.cpp | 2 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 9 +------- .../templateInterpreterGenerator_riscv.cpp | 2 +- src/hotspot/cpu/s390/downcallLinker_s390.cpp | 2 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 16 ++++--------- .../templateInterpreterGenerator_s390.cpp | 20 ++++------------ src/hotspot/cpu/x86/downcallLinker_x86_64.cpp | 2 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 9 +------- .../x86/templateInterpreterGenerator_x86.cpp | 2 +- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 2 +- src/hotspot/share/prims/forte.cpp | 5 ---- src/hotspot/share/runtime/javaThread.cpp | 11 +-------- src/hotspot/share/runtime/safepoint.cpp | 6 ++--- src/hotspot/share/runtime/vframe.inline.hpp | 6 ----- src/hotspot/share/runtime/vmStructs.cpp | 5 ---- src/hotspot/share/services/threadService.cpp | 2 +- .../share/utilities/globalDefinitions.hpp | 23 +++++-------------- .../sun/jvm/hotspot/runtime/JavaThread.java | 20 ---------------- .../jvm/hotspot/runtime/JavaThreadState.java | 11 --------- 27 files changed, 42 insertions(+), 175 deletions(-) diff --git a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp index 130d29498007..db0d5e007a02 100644 --- a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp @@ -308,7 +308,7 @@ void DowncallLinker::StubGenerator::generate() { // Restore cpu control state after JNI call __ restore_cpu_control_state_after_jni(rscratch1, tmp1); - __ mov(tmp1, _thread_in_native_trans); + __ mov(tmp1, _thread_in_vm); __ strw(tmp1, Address(rthread, JavaThread::thread_state_offset())); // Force this write out before the read below diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index cb14d3eada1e..60065ab19406 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -2047,14 +2047,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label safepoint_in_progress, safepoint_in_progress_done; - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ mov(rscratch1, _thread_in_native_trans); + __ mov(rscratch1, _thread_in_vm); __ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset())); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index dacb47d15944..9c53800dd34b 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1422,7 +1422,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ verify_sve_vector_length(); // change thread state - __ mov(rscratch1, _thread_in_native_trans); + __ mov(rscratch1, _thread_in_vm); __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index d471cf6ce334..593ba159aa7b 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1263,9 +1263,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ c2bool(R0); } - // Do a safepoint check while thread is in transition state + // Do a safepoint check Label call_safepoint_runtime, return_to_java; - __ mov(Rtemp, _thread_in_native_trans); + __ mov(Rtemp, _thread_in_vm); __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); // make sure the store is observed before reading the SafepointSynchronize state and further mem refs diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index 6ecdc29cf451..99f30a8f2669 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -1014,7 +1014,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { } // Do safepoint check - __ mov(Rtemp, _thread_in_native_trans); + __ mov(Rtemp, _thread_in_vm); __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); // Force this write out before the read below diff --git a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp index d149fc33ac38..d550c33b1122 100644 --- a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp @@ -297,7 +297,7 @@ void DowncallLinker::StubGenerator::generate() { Label L_after_reguard; if (_needs_transition) { - __ li(tmp, _thread_in_native_trans); + __ li(tmp, _thread_in_vm); __ release(); __ stw(tmp, in_bytes(JavaThread::thread_state_offset()), R16_thread); if (!UseSystemMemoryBarrier) { diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 364ed7de3b07..553934953873 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2617,21 +2617,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, } // Publish thread state - // -------------------------------------------------------------------------- - - // Switch thread to "native transition" state before reading the - // synchronization state. This additional state is necessary because reading - // and testing the synchronization state is not atomic w.r.t. GC, as this - // scenario demonstrates: - // - Java thread A, in _thread_in_native state, loads _not_synchronized - // and is preempted. - // - VM thread changes sync state to synchronizing and suspends threads - // for GC. - // - Thread A is resumed to finish this native method, but doesn't block - // here since it didn't see any synchronization in progress, and escapes. - - // Transition from _thread_in_native to _thread_in_native_trans. - __ li(R0, _thread_in_native_trans); + // Transition from _thread_in_native to _thread_in_vm. + __ li(R0, _thread_in_vm); __ release(); // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); __ stw(R0, thread_(thread_state)); @@ -2682,10 +2669,10 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Publish thread state. // -------------------------------------------------------------------------- - // Thread state is thread_in_native_trans. Any safepoint blocking has + // Thread state is _thread_in_vm. Any safepoint blocking has // already happened so we can now change state to _thread_in_Java. - // Transition from _thread_in_native_trans to _thread_in_Java. + // Transition from _thread_in_vm to _thread_in_Java. __ li(R0, _thread_in_Java); __ lwsync(); // Acquire safepoint and suspend state, release thread state. // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 0fee34392847..35042e841e66 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1484,21 +1484,10 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // In order for GC to work, don't clear the last_Java_sp until after // blocking. - //============================================================================= - // Switch thread to "native transition" state before reading the - // synchronization state. This additional state is necessary - // because reading and testing the synchronization state is not - // atomic w.r.t. GC, as this scenario demonstrates: Java thread A, - // in _thread_in_native state, loads _not_synchronized and is - // preempted. VM thread changes sync state to synchronizing and - // suspends threads for GC. Thread A is resumed to finish this - // native method, but doesn't block here since it didn't see any - // synchronization in progress, and escapes. - // We use release_store_fence to update values like the thread state, where // we don't want the current thread to continue until all our prior memory // accesses (including the new thread state) are visible to other threads. - __ li(R0/*thread_state*/, _thread_in_native_trans); + __ li(R0/*thread_state*/, _thread_in_vm); __ release(); __ stw(R0/*thread_state*/, thread_(thread_state)); if (!UseSystemMemoryBarrier) { @@ -1506,9 +1495,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { } // Now before we return to java we must look for a current safepoint - // (a new safepoint can not start since we entered native_trans). - // We must check here because a current safepoint could be modifying - // the callers registers right this moment. + // (a new safepoint can not start since we entered _thread_in_vm). + // We must check here because a current safepoint could be in progress. // Acquire isn't strictly necessary here because of the fence, but // sync_state is declared to be volatile, so we do it anyway @@ -1538,7 +1526,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { //============================================================================= // <<<<<< Back in Interpreter Frame >>>>> - // We are in thread_in_native_trans here and back in the normal + // We are in _thread_in_vm here and back in the normal // interpreter frame. We don't have to do anything special about // safepoints and we can switch to Java mode anytime we are ready. diff --git a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp index f9d7ce78ff0e..b11abb912ee5 100644 --- a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp @@ -308,7 +308,7 @@ void DowncallLinker::StubGenerator::generate() { __ restore_cpu_control_state_after_jni(t0); __ block_comment("{ thread native2java"); - __ mv(t0, _thread_in_native_trans); + __ mv(t0, _thread_in_vm); __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); // Force this write out before the read below diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index ec0a5f5d9b3a..f28230f23bc5 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1817,14 +1817,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label safepoint_in_progress, safepoint_in_progress_done; - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ mv(t0, _thread_in_native_trans); + __ mv(t0, _thread_in_vm); __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index b5b1b89ca72a..ef23498da5c7 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1213,7 +1213,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // Force all preceding writes to be observed prior to thread state change __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ mv(t0, _thread_in_native_trans); + __ mv(t0, _thread_in_vm); __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); // Force this write out before the read below diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index f1c41d05b5cf..4fe4c31567a0 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -247,7 +247,7 @@ void DowncallLinker::StubGenerator::generate() { if (_needs_transition) { __ block_comment("thread_native2java {"); - __ set_thread_state(_thread_in_native_trans); + __ set_thread_state(_thread_in_vm); if (!UseSystemMemoryBarrier) { __ z_fence(); // Order state change wrt. safepoint poll. diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 06b6b74c9fd9..b6b22102d011 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2745,16 +2745,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, break; } - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // - Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // - VM thread changes sync state to synchronizing and suspends threads for GC. - // - Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization in progress, and escapes. - - // Transition from _thread_in_native to _thread_in_native_trans. - __ set_thread_state(_thread_in_native_trans); + // Transition from _thread_in_native to _thread_in_vm. + __ set_thread_state(_thread_in_vm); // Safepoint synchronization //-------------------------------------------------------------------- @@ -2795,10 +2787,10 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, } //-------------------------------------------------------------------- - // Thread state is thread_in_native_trans. Any safepoint blocking has + // Thread state is _thread_in_vm. Any safepoint blocking has // already happened so we can now change state to _thread_in_Java. //-------------------------------------------------------------------- - // Transition from _thread_in_native_trans to _thread_in_Java. + // Transition from _thread_in_vm to _thread_in_Java. __ set_thread_state(_thread_in_Java); // Check preemption for Object.wait() diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index 8e235a8c3c87..c0a1b06954da 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -1575,26 +1575,14 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // In order for GC to work, don't clear the last_Java_sp until after // blocking. - //============================================================================= - // Switch thread to "native transition" state before reading the - // synchronization state. This additional state is necessary - // because reading and testing the synchronization state is not - // atomic w.r.t. GC, as this scenario demonstrates: Java thread A, - // in _thread_in_native state, loads _not_synchronized and is - // preempted. VM thread changes sync state to synchronizing and - // suspends threads for GC. Thread A is resumed to finish this - // native method, but doesn't block here since it didn't see any - // synchronization is progress, and escapes. - - __ set_thread_state(_thread_in_native_trans); + __ set_thread_state(_thread_in_vm); if (!UseSystemMemoryBarrier) { __ z_fence(); } // Now before we return to java we must look for a current safepoint - // (a new safepoint can not start since we entered native_trans). - // We must check here because a current safepoint could be modifying - // the callers registers right this moment. + // (a new safepoint can not start since we entered _thread_in_vm). + // We must check here because a current safepoint could be in progress. // Check for safepoint operation in progress and/or pending suspend requests. { @@ -1612,7 +1600,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { //============================================================================= // Back in Interpreter Frame. - // We are in thread_in_native_trans here and back in the normal + // We are in _thread_in_vm here and back in the normal // interpreter frame. We don't have to do anything special about // safepoints and we can switch to Java mode anytime we are ready. diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp index e3bf5f17fe9b..2480e68e7b86 100644 --- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp @@ -310,7 +310,7 @@ void DowncallLinker::StubGenerator::generate() { __ block_comment("{ thread native2java"); __ restore_cpu_control_state_after_jni(rscratch1); - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans); + __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_vm); // Force this write out before the read below if (!UseSystemMemoryBarrier) { diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 37df7acf9426..8d257565c939 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2456,14 +2456,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, default : ShouldNotReachHere(); } - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans); + __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_vm); // Force this write out before the read below if (!UseSystemMemoryBarrier) { diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 7da01709d726..631d23801d33 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -956,7 +956,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // change thread state __ movl(Address(thread, JavaThread::thread_state_offset()), - _thread_in_native_trans); + _thread_in_vm); // Force this write out before the read below if (!UseSystemMemoryBarrier) { diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 810d9db8d58e..89a021ddb294 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -427,7 +427,7 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // ThreadStateTransition::transition_from_native() cannot be used // here because it does not check for asynchronous exceptions. // We have to manage the transition ourself. - thread->set_thread_state_fence(_thread_in_native_trans); + thread->set_thread_state_fence(_thread_in_vm); // Handle safepoint operations, pending suspend requests, // and pending asynchronous exceptions. diff --git a/src/hotspot/share/prims/forte.cpp b/src/hotspot/share/prims/forte.cpp index 10e8b45dc75a..0e0f0e8a6e2e 100644 --- a/src/hotspot/share/prims/forte.cpp +++ b/src/hotspot/share/prims/forte.cpp @@ -612,17 +612,13 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { switch (thread->thread_state()) { case _thread_new: case _thread_uninitialized: - case _thread_new_trans: // We found the thread on the threads list above, but it is too // young to be useful so return that there are no Java frames. trace->num_frames = 0; break; case _thread_in_native: - case _thread_in_native_trans: case _thread_blocked: - case _thread_blocked_trans: case _thread_in_vm: - case _thread_in_vm_trans: { frame fr; @@ -648,7 +644,6 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { } break; case _thread_in_Java: - case _thread_in_Java_trans: { frame fr; diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 8e5fde069c68..fc593b7f4364 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1099,14 +1099,10 @@ void JavaThread::verify_not_published() { // Slow path when the native==>Java barriers detect a safepoint/handshake is // pending, when _suspend_flags is non-zero or when we need to process a stack // watermark. Also check for pending async exceptions (except unsafe access error). -// Note only the native==>Java barriers can call this function when thread state -// is _thread_in_native_trans. void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) { - assert(thread->thread_state() == _thread_in_native_trans, "wrong state"); + assert(thread->thread_state() == _thread_in_vm, "wrong state"); assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition"); - thread->set_thread_state(_thread_in_vm); - // Enable WXWrite: called directly from interpreter native wrapper. MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread)); @@ -1333,15 +1329,10 @@ static const char* _get_thread_state_name(JavaThreadState _thread_state) { switch (_thread_state) { case _thread_uninitialized: return "_thread_uninitialized"; case _thread_new: return "_thread_new"; - case _thread_new_trans: return "_thread_new_trans"; case _thread_in_native: return "_thread_in_native"; - case _thread_in_native_trans: return "_thread_in_native_trans"; case _thread_in_vm: return "_thread_in_vm"; - case _thread_in_vm_trans: return "_thread_in_vm_trans"; case _thread_in_Java: return "_thread_in_Java"; - case _thread_in_Java_trans: return "_thread_in_Java_trans"; case _thread_blocked: return "_thread_blocked"; - case _thread_blocked_trans: return "_thread_blocked_trans"; default: return "unknown thread state"; } } diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 5f01b7ac311b..85ae8b800f5e 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -297,9 +297,9 @@ void SafepointSynchronize::arm_safepoint() { // 4. Blocked // A thread which is blocked will not be allowed to return from the // block condition until the safepoint operation is complete. - // 5. In VM or Transitioning between states - // If a Java thread is currently running in the VM or transitioning - // between states, the safepointing code will poll the thread state + // 5. In VM + // If a Java thread is currently running in the VM, + // the safepointing code will poll the thread state // until the thread blocks itself when it attempts transitions to a // new state or locking a safepoint checked monitor. diff --git a/src/hotspot/share/runtime/vframe.inline.hpp b/src/hotspot/share/runtime/vframe.inline.hpp index b3e7b2800c54..58d06771eb5f 100644 --- a/src/hotspot/share/runtime/vframe.inline.hpp +++ b/src/hotspot/share/runtime/vframe.inline.hpp @@ -235,12 +235,6 @@ inline bool vframeStreamCommon::fill_from_frame() { JavaThreadState state = _thread != nullptr ? _thread->thread_state() : _thread_in_Java; - // in_Java should be good enough to test safepoint safety - // if state were say in_Java_trans then we'd expect that - // the pc would have already been slightly adjusted to - // one that would produce a pcDesc since the trans state - // would be one that might in fact anticipate a safepoint - if (state == _thread_in_Java ) { // This will get a method a zero bci and no inlining. // Might be nice to have a unique bci to signify this diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 20245684710d..3196b6f31ef3 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1372,15 +1372,10 @@ \ declare_constant(_thread_uninitialized) \ declare_constant(_thread_new) \ - declare_constant(_thread_new_trans) \ declare_constant(_thread_in_native) \ - declare_constant(_thread_in_native_trans) \ declare_constant(_thread_in_vm) \ - declare_constant(_thread_in_vm_trans) \ declare_constant(_thread_in_Java) \ - declare_constant(_thread_in_Java_trans) \ declare_constant(_thread_blocked) \ - declare_constant(_thread_blocked_trans) \ declare_constant(JavaThread::_not_terminated) \ declare_constant(JavaThread::_thread_exiting) \ \ diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 5c9e6ad166a8..6e18732284b3 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1095,7 +1095,7 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread, for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { // skips JavaThreads in the process of exiting // and also skips VM internal JavaThreads - // Threads in _thread_new or _thread_new_trans state are included. + // Threads in _thread_new state are included. // i.e. threads have been started but not yet running. if (jt->threadObj() == nullptr || jt->is_exiting() || diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 5e6a7c04a0bd..6d3421bd2cf8 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1018,25 +1018,14 @@ TosState as_TosState(BasicType type); // _thread_in_vm : Executing in the vm // _thread_in_Java : Executing either interpreted or compiled Java code (or could be in a stub) // -// Each state has an associated xxxx_trans state, which is an intermediate state used when a thread is in -// a transition from one state to another. These extra states makes it possible for the safepoint code to -// handle certain thread_states without having to suspend the thread - making the safepoint code faster. -// -// Given a state, the xxxx_trans state can always be found by adding 1. -// enum JavaThreadState { _thread_uninitialized = 0, // should never happen (missing initialization) - _thread_new = 2, // just starting up, i.e., in process of being initialized - _thread_new_trans = 3, // corresponding transition state (not used, included for completeness) - _thread_in_native = 4, // running in native code - _thread_in_native_trans = 5, // corresponding transition state - _thread_in_vm = 6, // running in VM - _thread_in_vm_trans = 7, // corresponding transition state - _thread_in_Java = 8, // running in Java or in stub code - _thread_in_Java_trans = 9, // corresponding transition state (not used, included for completeness) - _thread_blocked = 10, // blocked in vm - _thread_blocked_trans = 11, // corresponding transition state - _thread_max_state = 12 // maximum thread state+1 - used for statistics allocation + _thread_new , // just starting up, i.e., in process of being initialized + _thread_in_native , // running in native code + _thread_in_vm , // running in VM + _thread_in_Java , // running in Java or in stub code + _thread_blocked , // blocked in vm + _thread_max_state // maximum thread state+1 - used for statistics allocation }; //---------------------------------------------------------------------------------------------------- diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java index c18bcf8cd377..acff2c2643eb 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java @@ -58,15 +58,10 @@ public class JavaThread extends Thread { // JavaThreadStates read from underlying process private static int UNINITIALIZED; private static int NEW; - private static int NEW_TRANS; private static int IN_NATIVE; - private static int IN_NATIVE_TRANS; private static int IN_VM; - private static int IN_VM_TRANS; private static int IN_JAVA; - private static int IN_JAVA_TRANS; private static int BLOCKED; - private static int BLOCKED_TRANS; private static int NOT_TERMINATED; private static int EXITING; @@ -106,15 +101,10 @@ private static synchronized void initialize(TypeDataBase db) { UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); NEW = db.lookupIntConstant("_thread_new").intValue(); - NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue(); IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue(); - IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue(); IN_VM = db.lookupIntConstant("_thread_in_vm").intValue(); - IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue(); IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue(); - IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue(); BLOCKED = db.lookupIntConstant("_thread_blocked").intValue(); - BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue(); NOT_TERMINATED = db.lookupIntConstant("JavaThread::_not_terminated").intValue(); EXITING = db.lookupIntConstant("JavaThread::_thread_exiting").intValue(); @@ -293,24 +283,14 @@ public JavaThreadState getThreadState() { return JavaThreadState.UNINITIALIZED; } else if (val == NEW) { return JavaThreadState.NEW; - } else if (val == NEW_TRANS) { - return JavaThreadState.NEW_TRANS; } else if (val == IN_NATIVE) { return JavaThreadState.IN_NATIVE; - } else if (val == IN_NATIVE_TRANS) { - return JavaThreadState.IN_NATIVE_TRANS; } else if (val == IN_VM) { return JavaThreadState.IN_VM; - } else if (val == IN_VM_TRANS) { - return JavaThreadState.IN_VM_TRANS; } else if (val == IN_JAVA) { return JavaThreadState.IN_JAVA; - } else if (val == IN_JAVA_TRANS) { - return JavaThreadState.IN_JAVA_TRANS; } else if (val == BLOCKED) { return JavaThreadState.BLOCKED; - } else if (val == BLOCKED_TRANS) { - return JavaThreadState.BLOCKED_TRANS; } else { throw new RuntimeException("Illegal thread state " + val); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java index a89f61369c95..52b1e1932187 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java @@ -35,25 +35,14 @@ public class JavaThreadState { public static final JavaThreadState UNINITIALIZED = new JavaThreadState("UNINITIALIZED"); /** Just starting up, i.e., in process of being initialized */ public static final JavaThreadState NEW = new JavaThreadState("NEW"); - /** Corresponding transition state (not used, included for completeness) */ - public static final JavaThreadState NEW_TRANS = new JavaThreadState("NEW_TRANS"); /** Running in native code */ public static final JavaThreadState IN_NATIVE = new JavaThreadState("IN_NATIVE"); - /** Corresponding transition state */ - public static final JavaThreadState IN_NATIVE_TRANS = new JavaThreadState("IN_NATIVE_TRANS"); /** Running in VM */ public static final JavaThreadState IN_VM = new JavaThreadState("IN_VM"); - /** Corresponding transition state */ - public static final JavaThreadState IN_VM_TRANS = new JavaThreadState("IN_VM_TRANS"); /** Running in Java or in stub code */ public static final JavaThreadState IN_JAVA = new JavaThreadState("IN_JAVA"); - /** Corresponding transition state (not used, included for completeness) */ - public static final JavaThreadState IN_JAVA_TRANS = new JavaThreadState("IN_JAVA_TRANS"); /** Blocked in vm */ public static final JavaThreadState BLOCKED = new JavaThreadState("BLOCKED"); - /** Corresponding transition state */ - public static final JavaThreadState BLOCKED_TRANS = new JavaThreadState("BLOCKED_TRANS"); - /** Special state needed, since we cannot suspend a thread when it is in native_trans */ private JavaThreadState(String stringVal) { this.stringVal = stringVal; From 9255c103d0fec0c61904a6214053591b91a6c14e Mon Sep 17 00:00:00 2001 From: Srinivas Vamsi Parasa Date: Mon, 24 Aug 2026 21:15:53 +0000 Subject: [PATCH 059/223] 8381640: Enable UseAPX as a product feature Reviewed-by: sviswanathan, drwhite, kvn --- src/hotspot/cpu/x86/globals_x86.hpp | 2 +- src/hotspot/cpu/x86/vm_version_x86.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index c41be7a67724..66ed3abd0cc7 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -108,7 +108,7 @@ define_pd_global(bool, InlineTypeReturnedAsFields, true); "Highest supported AVX instructions set on x86/x64") \ range(0, 3) \ \ - product(bool, UseAPX, false, EXPERIMENTAL, \ + product(bool, UseAPX, false, \ "Use Intel Advanced Performance Extensions") \ \ product(bool, UseKNLSetting, false, DIAGNOSTIC, \ diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index bc882f395862..12cdadf026b6 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1061,8 +1061,7 @@ void VM_Version::get_processor_features() { // Currently APX support is only enabled for targets supporting AVX512VL feature. if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) { if (FLAG_IS_DEFAULT(UseAPX)) { - FLAG_SET_DEFAULT(UseAPX, false); // by default UseAPX is false - clear_feature(CPU_APX_F); + FLAG_SET_DEFAULT(UseAPX, true); // by default UseAPX is false; enable if supported. } else if (!UseAPX) { clear_feature(CPU_APX_F); } From fd596940e81dd79a00f6f6360ae63a1c15eddf91 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 25 Aug 2026 00:02:10 +0000 Subject: [PATCH 060/223] 8388310: AtomicReferenceFieldUpdater does not perform a substitutability check Reviewed-by: vklang, alanb --- .../atomic/AtomicReferenceFieldUpdater.java | 4 +- ...cReferenceFieldUpdaterValueObjectTest.java | 143 ++++++++++++++++++ 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/util/concurrent/atomic/AtomicReferenceFieldUpdaterValueObjectTest.java diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 3d47e8e323aa..0ee59922b015 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -449,14 +449,14 @@ static void throwCCE() { public final boolean compareAndSet(T obj, V expect, V update) { accessCheck(obj); valueCheck(update); - return U.compareAndSetReference(obj, offset, expect, update); + return U.compareAndSetReference(obj, offset, vclass, expect, update); } public final boolean weakCompareAndSet(T obj, V expect, V update) { // same implementation as strong form for now accessCheck(obj); valueCheck(update); - return U.compareAndSetReference(obj, offset, expect, update); + return U.compareAndSetReference(obj, offset, vclass, expect, update); } public final void set(T obj, V newValue) { diff --git a/test/jdk/java/util/concurrent/atomic/AtomicReferenceFieldUpdaterValueObjectTest.java b/test/jdk/java/util/concurrent/atomic/AtomicReferenceFieldUpdaterValueObjectTest.java new file mode 100644 index 000000000000..ee31ee8b0b3c --- /dev/null +++ b/test/jdk/java/util/concurrent/atomic/AtomicReferenceFieldUpdaterValueObjectTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8388310 + * @summary AtomicReferenceFieldUpdater does not perform a substitutability check + * @enablePreview + * @run junit ${test.main.class} + */ + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AtomicReferenceFieldUpdaterValueObjectTest { + volatile Integer x = null; + + static AtomicReferenceFieldUpdater updaterFor(String fieldName) { + return AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterValueObjectTest.class, Integer.class, fieldName); + } + + /** + * get returns the last value set or assigned + */ + @Test + public void testGetSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = new Integer(1); + assertSame(new Integer(1), a.get(this)); + a.set(this, new Integer(2)); + assertSame(new Integer(2), a.get(this)); + a.set(this, new Integer(-3)); + assertSame(new Integer(-3), a.get(this)); + } + + /** + * get returns the last value lazySet by same thread + */ + @Test + public void testGetLazySet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = new Integer(1); + assertSame(new Integer(1), a.get(this)); + a.lazySet(this, new Integer(2)); + assertSame(new Integer(2), a.get(this)); + a.lazySet(this, new Integer(-3)); + assertSame(new Integer(-3), a.get(this)); + } + + /** + * compareAndSet succeeds in changing value if same as expected else fails + */ + @Test + public void testCompareAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = new Integer(1); + assertTrue(a.compareAndSet(this, new Integer(1), new Integer(2))); + assertTrue(a.compareAndSet(this, new Integer(2), new Integer(-4))); + assertSame(new Integer(-4), a.get(this)); + assertFalse(a.compareAndSet(this, new Integer(-5), new Integer(7))); + assertNotSame(new Integer(7), a.get(this)); + assertSame(new Integer(-4), a.get(this)); + assertTrue(a.compareAndSet(this, new Integer(-4), new Integer(7))); + assertSame(new Integer(7), a.get(this)); + } + + /** + * compareAndSet in new Integer(1) thread enables another waiting for value + * to succeed + */ + @Test + public void testCompareAndSetInMultipleThreads() throws Exception { + x = new Integer(1); + final AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + + Thread t = Thread.startVirtualThread(() -> { + while (!a.compareAndSet(AtomicReferenceFieldUpdaterValueObjectTest.this, new Integer(2), new Integer(3))) + Thread.yield(); + }); + + assertTrue(a.compareAndSet(this, new Integer(1), new Integer(2))); + t.join(); + assertFalse(t.isAlive()); + assertSame(new Integer(3), a.get(this)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when same as expected + */ + @Test + public void testWeakCompareAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = new Integer(1); + do {} while (!a.weakCompareAndSet(this, new Integer(1), new Integer(2))); + do {} while (!a.weakCompareAndSet(this, new Integer(2), new Integer(-4))); + assertSame(new Integer(-4), a.get(this)); + do {} while (!a.weakCompareAndSet(this, new Integer(-4), new Integer(7))); + assertSame(new Integer(7), a.get(this)); + } + + /** + * getAndSet returns previous value and sets to given value + */ + @Test + public void testGetAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = new Integer(1); + assertSame(new Integer(1), a.getAndSet(this, new Integer(0))); + assertSame(new Integer(0), a.getAndSet(this, new Integer(-10))); + assertSame(new Integer(-10), a.getAndSet(this, new Integer(1))); + } + +} From 31b9dadce4eb25e3c2eb4d3073af4353f0fe320b Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Tue, 25 Aug 2026 02:49:22 +0000 Subject: [PATCH 061/223] 8390334: Remove deprecated println() method from nsk.share.Log Reviewed-by: cjplummer, coleenp, sspitsyn, dholmes --- .../nsk/jdb/hidden_class/hc001/hc001.java | 68 +++++++++---------- .../nsk/jdb/hidden_class/hc001/hc001a.java | 2 +- .../connect/connect001/connect001.java | 4 +- .../connect/connect002/connect002.java | 4 +- .../connect/connect003/connect003.java | 4 +- .../connect/connect004/connect004.java | 4 +- .../connect/connect005/connect005.java | 4 +- .../plugAttachConnect001.java | 4 +- .../plugAttachConnect002.java | 4 +- .../plugAttachConnect003.java | 4 +- .../plugLaunchConnect001.java | 4 +- .../plugLaunchConnect002.java | 4 +- .../plugLaunchConnect003.java | 4 +- .../plugListenConnect001.java | 4 +- .../plugListenConnect002.java | 4 +- .../plugListenConnect003.java | 4 +- .../plugMultiConnect001.java | 4 +- .../plugMultiConnect002.java | 4 +- .../plugMultiConnect003.java | 4 +- .../plugMultiConnect004.java | 4 +- .../plugMultiConnect005.java | 4 +- .../plugMultiConnect006.java | 4 +- .../transportService001.java | 4 +- .../transportService002.java | 4 +- .../transportService003.java | 4 +- .../jdi/ReferenceType/equals/equals001.java | 4 +- .../jdi/ReferenceType/equals/equals002.java | 2 +- .../failedToInitialize/failedtoinit002.java | 2 +- .../jdi/ReferenceType/fields/fields001.java | 4 +- .../jdi/ReferenceType/fields/fields003.java | 2 +- .../jdi/ReferenceType/fields/fields004.java | 4 +- .../genericSignature/genericSignature001.java | 4 +- .../genericSignature001a.java | 4 +- .../genericSignature/genericSignature002.java | 4 +- .../genericSignature002a.java | 4 +- .../ReferenceType/hashCode/hashcode001.java | 4 +- .../ReferenceType/hashCode/hashcode002.java | 2 +- .../isAbstract/isabstract002.java | 2 +- .../isInitialized/isinit001.java | 4 +- .../isInitialized/isinit002.java | 2 +- .../isPrepared/isprepared001.java | 4 +- .../isPrepared/isprepared002.java | 2 +- .../isVerified/isverified002.java | 2 +- .../jdi/ReferenceType/methods/methods001.java | 4 +- .../jdi/ReferenceType/methods/methods003.java | 2 +- .../jdi/ReferenceType/methods/methods004.java | 4 +- .../methodsByName_ss/methbyname_ss003.java | 2 +- .../nsk/jdi/ReferenceType/name/name001.java | 4 +- .../nsk/jdi/ReferenceType/name/name002.java | 2 +- .../sourceName/sourcename001.java | 4 +- .../sourceName/sourcename002.java | 2 +- .../sourceName/sourcename003.java | 2 +- .../genericSignature/genericSignature001.java | 4 +- .../genericSignature001a.java | 4 +- .../genericSignature/genericSignature002.java | 4 +- .../genericSignature002a.java | 4 +- .../createVirtualMachine/createVM001.java | 4 +- .../createVirtualMachine/createVM002.java | 4 +- .../createVirtualMachine/createVM003.java | 4 +- .../createVirtualMachine/createVM004.java | 4 +- .../createVirtualMachine/createVM005.java | 4 +- .../jdwp/Event/CLASS_UNLOAD/clsunload001.java | 4 +- .../ForceGarbageCollection/forcegc001.java | 6 +- .../hotswap/HS104/hs104t002/hs104t002.java | 10 +-- .../hotswap/HS202/hs202t002/hs202t002.java | 4 +- .../hotswap/HS203/hs203t001/hs203t001.java | 2 +- .../hotswap/HS203/hs203t002/hs203t002.java | 4 +- .../hotswap/HS301/hs301t001/hs301t001.java | 10 +-- .../hotswap/HS302/hs302t002/hs302t002.java | 8 +-- .../hotswap/HS302/hs302t003/hs302t003.java | 8 +-- .../hotswap/HS302/hs302t004/hs302t004.java | 12 ++-- .../hotswap/HS302/hs302t005/hs302t005.java | 10 +-- .../hotswap/HS302/hs302t006/hs302t006.java | 4 +- .../hotswap/HS302/hs302t007/hs302t007.java | 10 +-- .../hotswap/HS302/hs302t008/hs302t008.java | 10 +-- .../hotswap/HS302/hs302t011/hs302t011.java | 6 +- .../hotswap/HS302/hs302t012/hs302t012.java | 6 +- .../vmTestbase/nsk/share/IORedirector.java | 4 +- .../jtreg/vmTestbase/nsk/share/Log.java | 19 +----- .../vmTestbase/nsk/share/jdb/JdbTest.java | 2 +- 80 files changed, 203 insertions(+), 216 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java index a7c74e28aaec..9a818d01832e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,33 +88,33 @@ static void throwFailure(String msg) throws Failure { private String runPrologue() { String[] reply = null; - log.println("\n### Debugger: runPrologue"); + log.display("\n### Debugger: runPrologue"); // uncomment this line to enable verbose output from jdb // log.enableVerbose(true); // run jdb command "stop in" jdb.setBreakpointInMethod(EMPTY_METHOD_NAME); - log.println("\nDebugger: breakpoint is set at:\n\t" + EMPTY_METHOD_NAME); + log.display("\nDebugger: breakpoint is set at:\n\t" + EMPTY_METHOD_NAME); // run jdb command "cont" reply = jdb.receiveReplyFor(JdbCommand.cont); if (!jdb.isAtBreakpoint(reply, EMPTY_METHOD_NAME)) { throwFailure("Debugger: Missed breakpoint at:\n\t" + EMPTY_METHOD_NAME); } - log.println("\nDebugger: breakpoint is hit at:\n\t" + EMPTY_METHOD_NAME); + log.display("\nDebugger: breakpoint is hit at:\n\t" + EMPTY_METHOD_NAME); // run jdb command "eval" for hidden class field HC_NAME_FIELD reply = jdb.receiveReplyFor(JdbCommand.eval + HC_NAME_FIELD); int beg = reply[0].indexOf('"') + 1; int end = reply[0].lastIndexOf('"'); if (end == -1 || beg > end) { - log.println("\nDebugger: the jdb command:\n\t" + JdbCommand.eval + HC_NAME_FIELD); - log.println("\treturned bad reply:\n\t" + reply[0]); + log.display("\nDebugger: the jdb command:\n\t" + JdbCommand.eval + HC_NAME_FIELD); + log.display("\treturned bad reply:\n\t" + reply[0]); throwFailure("Debugger: failed to evaluate debuggee field:\n\t" + HC_NAME_FIELD); } String hiddenClassName = reply[0].substring(beg, end); // we know the hidden class name now - log.println("\nDebugger: jdb command eval returned hidden class name:\n\t" + hiddenClassName); + log.display("\nDebugger: jdb command eval returned hidden class name:\n\t" + hiddenClassName); return hiddenClassName; } @@ -123,21 +123,21 @@ private String runPrologue() { private void testClassCommands(String hcName) { String[] reply = null; - log.println("\n### Debugger: testClassCommands"); + log.display("\n### Debugger: testClassCommands"); // run jdb command "classes" reply = jdb.receiveReplyFor(JdbCommand.classes); if (!checkPattern(reply, hcName)) { throwFailure("Debugger: expected jdb command classes to list hidden class:\n\t" + hcName); } - log.println("\nDebugger: found matched class in jdb command classes reply:\n\t" + hcName); + log.display("\nDebugger: found matched class in jdb command classes reply:\n\t" + hcName); // run jdb command "class" for hidden class reply = jdb.receiveReplyFor(JdbCommand._class + hcName); if (!checkPattern(reply, hcName)) { throwFailure("Debugger: expected hiddenclass name in jdb command class reply: " + hcName); } - log.println("\nDebugger: found matched class in jdb command class reply:\n\t" + hcName); + log.display("\nDebugger: found matched class in jdb command class reply:\n\t" + hcName); } /* Transition the debuggee's execution to the hidden class method start. */ @@ -145,22 +145,22 @@ private void stopInHiddenClassMethod(String hcName) { String hcMethodName = hcName + "." + HC_METHOD_NAME; String[] reply = null; - log.println("\n### Debugger: stopInHiddenClassMethod"); + log.display("\n### Debugger: stopInHiddenClassMethod"); // set a breakpoint in hidden class method hcMethodName() jdb.setBreakpointInMethod(hcMethodName); - log.println("\nDebugger: breakpoint is set at:\n\t" + hcMethodName); + log.display("\nDebugger: breakpoint is set at:\n\t" + hcMethodName); // run jdb command "clear": should list breakpoint in hcMethodName reply = jdb.receiveReplyFor(JdbCommand.clear); if (!checkPattern(reply, hcMethodName)) { throwFailure("Debugger: expected jdb clear command to list breakpoint: " + hcMethodName); } - log.println("\nDebugger: jdb command clear lists breakpoint at:\n\t" + hcMethodName); + log.display("\nDebugger: jdb command clear lists breakpoint at:\n\t" + hcMethodName); // run jdb command "cont" jdb.receiveReplyFor(JdbCommand.cont); - log.println("\nDebugger: executed jdb command cont"); + log.display("\nDebugger: executed jdb command cont"); } /* Test the jdb commands "up" and "where" for hidden class. */ @@ -168,25 +168,25 @@ private void testUpWhereCommands(String hcName) { String hcMethodName = hcName + "." + HC_METHOD_NAME; String[] reply = null; - log.println("\n### Debugger: testUpWhereCommands"); + log.display("\n### Debugger: testUpWhereCommands"); // run jdb command "where": should list hcMethodName frame reply = jdb.receiveReplyFor(JdbCommand.where); if (!checkPattern(reply, hcMethodName)) { throwFailure("Debugger: jdb command where does not show expected frame: " + hcMethodName); } - log.println("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName); + log.display("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName); // run jdb command "up" jdb.receiveReplyFor(JdbCommand.up); - log.println("\nDebugger: executed jdb command up"); + log.display("\nDebugger: executed jdb command up"); // run jdb command "where": should not list hcMethodName frame reply = jdb.receiveReplyFor(JdbCommand.where); if (checkPattern(reply, hcMethodName)) { throwFailure("Debugger: jdb command where showed unexpected frame: " + hcMethodName); } - log.println("\nDebugger: jdb command where does not show unexpected frame:\n\t" + hcMethodName); + log.display("\nDebugger: jdb command where does not show unexpected frame:\n\t" + hcMethodName); } /* Test the jdb commands "down" and "where" for hidden class. */ @@ -194,39 +194,39 @@ private void testDownWhereCommands(String hcName) { String hcMethodName = hcName + "." + HC_METHOD_NAME; String[] reply = null; - log.println("\n### Debugger: testDownWhereCommands"); + log.display("\n### Debugger: testDownWhereCommands"); // run jdb command "down" jdb.receiveReplyFor(JdbCommand.down); - log.println("\nDebugger: executed jdb command down"); + log.display("\nDebugger: executed jdb command down"); // run jdb command "where": should list hcMethodName frame again reply = jdb.receiveReplyFor(JdbCommand.where); if (!checkPattern(reply, hcMethodName)) { throwFailure("Debugger: jdb command where does not show expected frame: " + hcMethodName); } - log.println("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName); + log.display("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName); } /* Test the jdb commands "fields" and "methods" for hidden class. */ private void testFieldsMethods(String hcName) { String[] reply = null; - log.println("\n### Debugger: testFieldsMethods"); + log.display("\n### Debugger: testFieldsMethods"); // run jdb command "methods" for hidden class reply = jdb.receiveReplyFor(JdbCommand.methods + hcName); if (!checkPattern(reply, hcName)) { throwFailure("Debugger: no expected hidden class name in its methods: " + hcName); } - log.println("\nDebugger: jdb command \"methods\" showed expected method:\n\t" + HC_METHOD_NAME); + log.display("\nDebugger: jdb command \"methods\" showed expected method:\n\t" + HC_METHOD_NAME); // run jdb command "fields" for hidden class reply = jdb.receiveReplyFor(JdbCommand.fields + hcName); if (!checkPattern(reply, HC_FIELD_NAME)) { throwFailure("Debugger: no expected hidden class field in its fields: " + HC_FIELD_NAME); } - log.println("\nDebugger: jdb command \"fields\" showed expected field:\n\t" + HC_FIELD_NAME); + log.display("\nDebugger: jdb command \"fields\" showed expected field:\n\t" + HC_FIELD_NAME); } /* Test the jdb commands "watch" and "unwatch" for hidden class. */ @@ -234,14 +234,14 @@ private void testWatchCommands(String hcName) { String hcFieldName = hcName + "." + HC_FIELD_NAME; String[] reply = null; - log.println("\n### Debugger: testWatchCommands"); + log.display("\n### Debugger: testWatchCommands"); // run jdb command "watch" for hidden class field HC_FIELD_NAME reply = jdb.receiveReplyFor(JdbCommand.watch + hcFieldName); if (!checkPattern(reply, HC_FIELD_NAME)) { throwFailure("Debugger: was not able to set watch point: " + hcFieldName); } - log.println("\nDebugger: jdb command \"watch\" added expected field to watch:\n\t" + hcFieldName); + log.display("\nDebugger: jdb command \"watch\" added expected field to watch:\n\t" + hcFieldName); // run jdb command "cont" jdb.receiveReplyFor(JdbCommand.cont); @@ -252,7 +252,7 @@ private void testWatchCommands(String hcName) { if (!checkPattern(reply, HC_FIELD_NAME)) { throwFailure("Debugger: expect field name in unwatch reply: " + hcFieldName); } - log.println("\nDebugger: jdb command \"unwatch\" removed expected field from watch:\n\t" + hcFieldName); + log.display("\nDebugger: jdb command \"unwatch\" removed expected field from watch:\n\t" + hcFieldName); } /* Test the jdb commands "eval", "print" and "dump" for hidden class. */ @@ -260,28 +260,28 @@ private void testEvalCommands(String hcName) { String hcFieldName = hcName + "." + HC_FIELD_NAME; String[] reply = null; - log.println("\n### Debugger: testEvalCommands"); + log.display("\n### Debugger: testEvalCommands"); // run jdb command "eval" for hidden class field HC_FIELD_NAME reply = jdb.receiveReplyFor(JdbCommand.eval + hcFieldName); if (!checkPattern(reply, hcFieldName)) { throwFailure("Debugger: expected field name in jdb command eval field reply: " + hcFieldName); } - log.println("\nDebugger: jdb command \"eval\" showed expected hidden class field name:\n\t" + hcFieldName); + log.display("\nDebugger: jdb command \"eval\" showed expected hidden class field name:\n\t" + hcFieldName); // run jdb command "print" for hidden class field HC_FIELD_NAME reply = jdb.receiveReplyFor(JdbCommand.print + hcFieldName); if (!checkPattern(reply, hcFieldName)) { throwFailure("Debugger: expected field name in jdb command print field reply: " + hcFieldName); } - log.println("\nDebugger: jdb command \"print\" showed expected hidden class field name:\n\t" + hcFieldName); + log.display("\nDebugger: jdb command \"print\" showed expected hidden class field name:\n\t" + hcFieldName); // execute jdb command "dump" for hidden class field HC_FIELD_NAME reply = jdb.receiveReplyFor(JdbCommand.dump + hcFieldName); if (!checkPattern(reply, hcFieldName)) { throwFailure("Debugger: expected field name in jdb command dump field reply: " + hcFieldName); } - log.println("\nDebugger: jdb command \"dump\" showed expected hidden class field name:\n\t" + hcFieldName); + log.display("\nDebugger: jdb command \"dump\" showed expected hidden class field name:\n\t" + hcFieldName); } /* Test the jdb command "watch" with an invalid class name. */ @@ -295,7 +295,7 @@ private void testInvWatchCommand(String hcName) { if (checkPattern(reply, "Deferring watch modification")) { throwFailure(MsgBase + " must not set deferred watch point"); } - log.println(MsgBase + " did not set deferred watch point"); + log.display(MsgBase + " did not set deferred watch point"); } /* Test the jdb command "eval" with an invalid class name. */ @@ -309,7 +309,7 @@ private void testInvEvalCommand(String hcName) { if (!checkPattern(reply, "ParseException")) { throwFailure(MsgBase + " must be rejected with ParseException"); } - log.println(MsgBase + " was rejected with ParseException"); + log.display(MsgBase + " was rejected with ParseException"); } /* Test the jdb commands "watch" and "eval" with various invalid class names. */ @@ -321,7 +321,7 @@ private void testInvalidCommands() { "xx.yyy.zzz/" }; - log.println("\n### Debugger: testInvalidCommands"); + log.display("\n### Debugger: testInvalidCommands"); // run jdb commands "watch" and "eval" with invalid class names for (int idx = 0; idx < invClassNames.length; idx++) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001a.java index 7946b5e65379..79a9599ac164 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java index 85cdbb279974..a23c1dde0197 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public static void main (String argv[]) { protected boolean shouldPass() { String feature = "com.sun.jdi.CommandLineLaunch"; if (argumentHandler.shouldPass(feature)) { - log.println("Test passes because of not implemented feature: " + feature); + log.display("Test passes because of not implemented feature: " + feature); return true; } return super.shouldPass(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java index a3219de0cc4e..8c592f366864 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public static void main (String argv[]) { protected boolean shouldPass() { String feature = "com.sun.jdi.SocketAttach"; if (argumentHandler.shouldPass(feature)) { - log.println("Test passes because of not implemented feature: " + feature); + log.display("Test passes because of not implemented feature: " + feature); return true; } return super.shouldPass(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java index 465e3c9deb24..8a65ea934a24 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public static void main (String argv[]) { protected boolean shouldPass() { String feature = "com.sun.jdi.SharedMemoryAttach"; if (argumentHandler.shouldPass(feature)) { - log.println("Test passes because of not implemented feature: " + feature); + log.display("Test passes because of not implemented feature: " + feature); return true; } return super.shouldPass(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java index 075e9c30268e..5396c7ff5fd9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public static void main (String argv[]) { protected boolean shouldPass() { String feature = "com.sun.jdi.SocketListen"; if (argumentHandler.shouldPass(feature)) { - log.println("Test passes because of not implemented feature: " + feature); + log.display("Test passes because of not implemented feature: " + feature); return true; } return super.shouldPass(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java index 7bd44a5927cc..f3d0e65f139f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ public class connect005 extends JdbTest { protected boolean shouldPass() { String feature = "com.sun.jdi.SharedMemoryListen"; if (argumentHandler.shouldPass(feature)) { - log.println("Test passes because of not implemented feature: " + feature); + log.display("Test passes because of not implemented feature: " + feature); return true; } return super.shouldPass(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect001/plugAttachConnect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect001/plugAttachConnect001.java index b1badcc533f0..218edd2c7d55 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect001/plugAttachConnect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect001/plugAttachConnect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,7 +122,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect002/plugAttachConnect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect002/plugAttachConnect002.java index 7c0f8fc83108..5695200a5d6c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect002/plugAttachConnect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect002/plugAttachConnect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,7 +140,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect003/plugAttachConnect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect003/plugAttachConnect003.java index 0bc4527ecf9f..6f54533b7a4e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect003/plugAttachConnect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/AttachConnector/plugAttachConnect003/plugAttachConnect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect001/plugLaunchConnect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect001/plugLaunchConnect001.java index 096e6b970af0..7a6a396e3cb7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect001/plugLaunchConnect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect001/plugLaunchConnect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect002/plugLaunchConnect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect002/plugLaunchConnect002.java index 71c0cc2987e3..bfa446ffa3b3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect002/plugLaunchConnect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect002/plugLaunchConnect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,7 +140,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect003/plugLaunchConnect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect003/plugLaunchConnect003.java index 2f5898dfd868..e4ea8fb27107 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect003/plugLaunchConnect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/LaunchConnector/plugLaunchConnect003/plugLaunchConnect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect001/plugListenConnect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect001/plugListenConnect001.java index bab07c442dd3..50a7dadb137b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect001/plugListenConnect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect001/plugListenConnect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect002/plugListenConnect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect002/plugListenConnect002.java index 2861c75491fc..09e441e008b4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect002/plugListenConnect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect002/plugListenConnect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,7 +140,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect003/plugListenConnect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect003/plugListenConnect003.java index 300af2f68516..37e869485929 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect003/plugListenConnect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/ListenConnector/plugListenConnect003/plugListenConnect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect001/plugMultiConnect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect001/plugMultiConnect001.java index 250b30a9472c..d89a534a3998 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect001/plugMultiConnect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect001/plugMultiConnect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,7 +151,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect002/plugMultiConnect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect002/plugMultiConnect002.java index b5f63b7e2ef1..80e79f774588 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect002/plugMultiConnect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect002/plugMultiConnect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect003/plugMultiConnect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect003/plugMultiConnect003.java index 6e883c779acb..5a5c55cc7d88 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect003/plugMultiConnect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect003/plugMultiConnect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,7 +189,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect004/plugMultiConnect004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect004/plugMultiConnect004.java index 00b57cb67316..b1b93bfaa5a0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect004/plugMultiConnect004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect004/plugMultiConnect004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect005/plugMultiConnect005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect005/plugMultiConnect005.java index 577cdd23f9d1..2adc52d5fc42 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect005/plugMultiConnect005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect005/plugMultiConnect005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,7 +213,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect006/plugMultiConnect006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect006/plugMultiConnect006.java index e753a3656fe4..e840f7c2fde1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect006/plugMultiConnect006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/MultiConnectors/plugMultiConnect006/plugMultiConnect006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,7 +238,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService001/transportService001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService001/transportService001.java index bf090ce7fa7e..d44875f84159 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService001/transportService001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService001/transportService001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,7 +160,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService002/transportService002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService002/transportService002.java index 370b5dbd7b31..db7a2567b333 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService002/transportService002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService002/transportService002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,7 +160,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService003/transportService003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService003/transportService003.java index 889942922b4d..b19810698457 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService003/transportService003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PlugConnectors/TransportService/transportService003/transportService003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001.java index 4d561c87d1b7..bba74edbaa01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java index 0686d73e69c7..3448a52b690f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java index f093fffe5032..4ff051ab3cde 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002.java @@ -81,7 +81,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001.java index 0e6bd85a1486..64cff44c397a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,7 +116,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java index dee295d20f27..42e359e29fe9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003.java @@ -81,7 +81,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004.java index bcfa4e323c1e..fcece8cefe23 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001.java index 20b473062b33..2ef55e3063c7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001a.java index 42c738fa86eb..6f8b59167257 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } // instantiating of arrays of primitive types for check ReferenceType.genericSignature() method diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002.java index 781b0f6f4ba6..1e3852838475 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002a.java index 2caa90e0a929..be72c7566db5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/genericSignature/genericSignature002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } // instantiating of non-generic interface types and arrays of non-generic interface types diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001.java index 57f08ebe7f04..123d1f12a495 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java index edca601544b9..403400499718 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java index 000054b284cc..7c7f15c03b19 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002.java @@ -81,7 +81,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java index 5674f53f5212..2046927d21ca 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,7 +94,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java index c95a3703e970..8f29bc0ba2e1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002.java @@ -81,7 +81,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java index 2eff33ed6c94..5b98a1ee949d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java index 4bd57d907910..604fde97babf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java index 2c89b8361f30..2ac8aaa99ea2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002.java @@ -83,7 +83,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001.java index b004aeb59c95..64de3285c972 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,7 +172,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java index 073699ea9bfe..739006c98fad 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004.java index fd86fd11b6c0..0d684445ea61 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java index 3dbead204935..ab3d21dcda5b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003.java @@ -83,7 +83,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001.java index bfd68bcae4f6..0a1600bbca02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java index a59821d1c148..1caec8899703 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001.java index 7840670aa438..352ee94815dc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java index 0db90110fbe3..d791b075cedb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002.java @@ -82,7 +82,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java index bd547529ec65..645f6229661e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003.java @@ -83,7 +83,7 @@ private static void print_log_on_verbose(String message) { } private static void print_log_anyway(String message) { - test_log_handler.println(message); + test_log_handler.display(message); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001.java index d5368568becc..3f9d74852cf0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001a.java index e479baa584bc..bef870721251 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } // primitive type fields and arrays of primitive types diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002.java index 8eabd51f7138..c0fdf0037c91 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002a.java index 476393e39cb5..adca0ea35bc6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/TypeComponent/genericSignature/genericSignature002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } // methods without generic signature diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM001.java index 26ad37078d80..1c5fa47e0d0e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002.java index dee135fbfedc..c2543a30350f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003.java index d1e8f67b2934..be08afe69622 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM004.java index 804a92b2b496..a22841750ae9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM005.java index aef6720f9171..2eb1f0e1efd5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachineManager/createVirtualMachine/createVM005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ private static void logOnError(String message) { } private static void logAlways(String message) { - logHandler.println(message); + logHandler.display(message); } public static void main (String argv[]) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/CLASS_UNLOAD/clsunload001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/CLASS_UNLOAD/clsunload001.java index ccfec8efeb9e..79aff2af8626 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/CLASS_UNLOAD/clsunload001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/CLASS_UNLOAD/clsunload001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -441,7 +441,7 @@ void waitForTestedEvent() { if (eventKind == JDWP.EventKind.VM_DEATH) { log.display("Got VM_DEATH event while waiting for tested event"); dead = true; - log.println("No CLASS_UNLOAD event occured at all so treat test as PASSED"); + log.display("No CLASS_UNLOAD event occured at all so treat test as PASSED"); return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ForceGarbageCollection/forcegc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ForceGarbageCollection/forcegc001.java index ffb5df089d8e..5f3523aca39c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ForceGarbageCollection/forcegc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ForceGarbageCollection/forcegc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ public int runIt(String argv[], PrintStream out) { log.display("Checking soft references " + kind + ": " + count + " references"); int found1 = checkObjects(count, refs, kind); if (found1 < found) { - log.println("# WARNING: " + found1 + " of " + found + log.display("# WARNING: " + found1 + " of " + found + " softly reachable objects were GCed\n" + "# by System.gc() but not by ForceGarbageCollection()"); } @@ -117,7 +117,7 @@ public int checkObjects(int count, SoftReference refs[], String kind) { } if (found > 0) { - log.println("# WARNING: " + found + " of " + count + log.display("# WARNING: " + found + " of " + count + " softly reachable objects not GCed " + kind); } else { log.display("All " + found + " of " + count diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/hs104t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/hs104t002.java index 6094caab16f9..253e62150f5b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/hs104t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/hs104t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,9 +112,9 @@ public boolean agentMethod() { pass=false; } if ( pass ) { - log.println(" Testcase hs104t002 :: Passed."); + log.display(" Testcase hs104t002 :: Passed."); } else { - log.println(" Testcase hs104t002 :: Failed."); + log.display(" Testcase hs104t002 :: Failed."); } return pass; } @@ -133,7 +133,7 @@ public boolean startAllThreads() { //notify all the threads to start their jobs. wicket.unlock(); started=true; - log.println(" startAllThreads :: All threads are running."); + log.display(" startAllThreads :: All threads are running."); } catch (IllegalStateException ise) { log.complain(" startAllThreads :: Error occured while" +" waiting for threads."); @@ -176,7 +176,7 @@ private boolean waitForAllThreads() { thread.join(); } allExited= true; - log.println(" All threads terminated without " + log.display(" All threads terminated without " +"java.lang.InterruptedException."); } catch(java.lang.InterruptedException ie ) { log.complain(" waitForAllThreads ::" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java index dd2951955439..5b8b2034bd02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java @@ -92,9 +92,9 @@ public boolean agentMethod() { boolean passed = false; if (successState == state && isRedefined()) { passed = true; - log.println(" ... Passed state (" + state + ")"); + log.display(" ... Passed state (" + state + ")"); } else { - log.println(" ... Failed state (" + state + ")"); + log.display(" ... Failed state (" + state + ")"); } return passed; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java index e42bede4e011..f561c26e6e1b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java @@ -79,7 +79,7 @@ public boolean agentMethod() { popThreadFrame(mt.getThread()); resumeThread(mt.getThread()); mt.join(); - log.println(" ..."+mt.threadState); + log.display(" ..."+mt.threadState); } catch(Exception ie) { ie.printStackTrace(); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java index f62bd49f674e..4623237058c6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java @@ -87,7 +87,7 @@ public boolean agentMethod() { resumeThread(mt.getThread()); MyThread.resume.set(true); mt.join(); - log.println(" ..."+mt.threadState); + log.display(" ..."+mt.threadState); } catch(Exception ie) { ie.printStackTrace(); } @@ -95,7 +95,7 @@ public boolean agentMethod() { if ( (mt.threadState < 1000) && (redefineAttempted() && isRedefined()) ) { passed = true; } else { - log.println(" FAILED ..."); + log.display(" FAILED ..."); } return passed; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS301/hs301t001/hs301t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS301/hs301t001/hs301t001.java index 1422d5802eae..d4e9c30b6e4b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS301/hs301t001/hs301t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS301/hs301t001/hs301t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,11 +85,11 @@ public boolean agentMethod() { } cls.doThis(); if (!pass) { - log.println(" Error occured, error in redefineing (as expected)."); - log.println(" Case passed."); + log.display(" Error occured, error in redefineing (as expected)."); + log.display(" Case passed."); } else { - log.println(" Successfully redefined, (which is not execpeted)."); - log.println(" Case failed."); + log.display(" Successfully redefined, (which is not execpeted)."); + log.display(" Case failed."); } return pass; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t002/hs302t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t002/hs302t002.java index 4a13fbc250c1..e46a572630b7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t002/hs302t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t002/hs302t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,14 +61,14 @@ public boolean agentMethod() { boolean pass=false; MyClass cls = new MyClass(); cls.setName("SOME NAME"); - log.println(" cls.toString() "+cls.toString()); + log.display(" cls.toString() "+cls.toString()); // Redefine should be attempted and failed. if (!cls.toString().equals("Default") && ( redefineAttempted() && !isRedefined()) ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } else { - log.println(" Failed .."); + log.display(" Failed .."); } return pass; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t003/hs302t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t003/hs302t003.java index 6cf324858185..c25885f53a82 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t003/hs302t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t003/hs302t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,13 +61,13 @@ public boolean agentMethod() { MyClass cls = new MyClass(); try { cls.setName("SOME NAME"); - log.println(" cls.toString() "+cls.toString()); + log.display(" cls.toString() "+cls.toString()); } catch(Exception exp) { if (cls.toString().equals("Default") && isRedefined() ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } else { - log.println(" Failed .."); + log.display(" Failed .."); } return pass; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t004/hs302t004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t004/hs302t004.java index ed8ec89ecf2d..36305b2589af 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t004/hs302t004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t004/hs302t004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,9 +65,9 @@ public boolean agentMethod(){ Method[] methods = klass.getDeclaredMethods(); for(Method method : methods) { if (method.getName().equals("setName")) { - log.println(" Modified "+method.getModifiers()); + log.display(" Modified "+method.getModifiers()); if ( (Modifier.PRIVATE & method.getModifiers())==Modifier.PRIVATE ) { - log.println("...Private.."); + log.display("...Private.."); pass = true; } } @@ -76,9 +76,9 @@ public boolean agentMethod(){ }catch(Exception exp) { if ( isRedefined() ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } else { - log.println(" Failed .."); + log.display(" Failed .."); } return pass; } @@ -86,7 +86,7 @@ public boolean agentMethod(){ if ( redefineAttempted() && !isRedefined() ) { pass = true; } - log.println(" PASS = "+pass); + log.display(" PASS = "+pass); return pass; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t005/hs302t005.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t005/hs302t005.java index e78e87992bdd..ae5c9ccdb56f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t005/hs302t005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t005/hs302t005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,10 +65,10 @@ public boolean agentMethod() { Method[] methods = klass.getDeclaredMethods(); for(Method method : methods) { if (method.getName().equals("setName")) { - log.println(" Modified "+method.getModifiers()); + log.display(" Modified "+method.getModifiers()); // Still its private good. if ( (Modifier.PRIVATE & method.getModifiers())==Modifier.PRIVATE ) { - log.println("...Private.."); + log.display("...Private.."); pass = true; } } @@ -76,14 +76,14 @@ public boolean agentMethod() { } catch(Exception exp) { if ( isRedefined() ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } } // If the execption is failed to throw. if ( redefineAttempted() && !isRedefined() ) { pass = true; } - log.println(" PASS = "+pass); + log.display(" PASS = "+pass); return pass; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t006/hs302t006.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t006/hs302t006.java index d4320dc9e8e4..5f9646e6393d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t006/hs302t006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t006/hs302t006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ public boolean agentMethod() { }catch(Exception exp) { if ( isRedefined() ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } } // If the execption is failed to throw. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t007/hs302t007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t007/hs302t007.java index 1c9c2924915e..92507e1cbb13 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t007/hs302t007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t007/hs302t007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,9 +66,9 @@ public boolean agentMethod() { Method[] methods = klass.getDeclaredMethods(); for(Method method : methods) { if (method.getName().equals("setName")) { - log.println(" Modified "+method.getModifiers()); + log.display(" Modified "+method.getModifiers()); if ( (Modifier.SYNCHRONIZED & method.getModifiers())==Modifier.SYNCHRONIZED ) { - log.println("...Synchronized.."); + log.display("...Synchronized.."); pass = true; } } @@ -76,9 +76,9 @@ public boolean agentMethod() { }catch(Exception exp) { if ( redefineAttempted() && !isRedefined()) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } else { - log.println(" Failed .."); + log.display(" Failed .."); } } return pass; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t008/hs302t008.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t008/hs302t008.java index e7d0323dcc8d..8dc396a346cb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t008/hs302t008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t008/hs302t008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,18 +75,18 @@ public boolean agentMethod(){ } }catch(Exception exp) { exp.printStackTrace(); - log.println(" Exception "+exp.getMessage()); + log.display(" Exception "+exp.getMessage()); if ( isRedefined() ) { pass =true; - log.println(" Passed .."); + log.display(" Passed .."); } else { - log.println(" Failed .."); + log.display(" Failed .."); } } if ( redefineAttempted() && !isRedefined() ) { pass = true; } - log.println(" PASS = "+pass); + log.display(" PASS = "+pass); return pass; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t011/hs302t011.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t011/hs302t011.java index 442e86b9bd75..018113a4daba 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t011/hs302t011.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t011/hs302t011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,12 +72,12 @@ public boolean agentMethod(){ } }catch(Exception exp) { exp.printStackTrace(); - log.println(" Exception "+exp.getMessage()); + log.display(" Exception "+exp.getMessage()); } if ( redefineAttempted() && !isRedefined() ) { pass = true; } - log.println(" PASS = "+pass); + log.display(" PASS = "+pass); return pass; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t012/hs302t012.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t012/hs302t012.java index 96295e50b569..4a17898f3c48 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t012/hs302t012.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS302/hs302t012/hs302t012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,12 +77,12 @@ public boolean agentMethod(){ } }catch(Exception exp) { exp.printStackTrace(); - log.println(" Exception "+exp.getMessage()); + log.display(" Exception "+exp.getMessage()); } if ( redefineAttempted() && !isRedefined() ) { pass = true; } - log.println(" PASS = "+pass); + log.display(" PASS = "+pass); return pass; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java b/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java index 19a58780a951..4b2e3b96d4c5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ public IORedirector(InputStream in, OutputStream out, String prefix) { public IORedirector(BufferedReader in, Log log, String prefix) { this(); this.bin = in; - addProcessor(s -> log.println(prefix + s)); + addProcessor(s -> log.display(prefix + s)); } public void addProcessor(Consumer lineProcessor) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index 2e038291759c..3bcf00603271 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -197,19 +197,6 @@ public static String printExceptionToString(Object prefix, Throwable exception) return bos.toString(); } - /** - * Print message to the assigned output stream. - * - * @deprecated Test ought to be quiet if log mode is non-verbose - * and there is no errors found by the test. Methods - * display() and complain() - * are enough for testing purposes. - */ - @Deprecated - public synchronized void println(String message) { - doPrint(message); - } - /** * Print trace message to the assigned output stream, * only if specified level is less or equal for the @@ -482,12 +469,12 @@ public void trace(int level, String message) { } /** - * Print message by invoking Log.println(). + * Print message by invoking Log.display(). * - * @see Log#println + * @see Log#display */ public void println(String message) { - log.println(makeLogMessage(message)); + log.display(makeLogMessage(message)); } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java index 11def178cdc5..c8fd40c2d4a0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java @@ -177,7 +177,7 @@ protected void runTest(String argv[]) { log = new Log(out, argumentHandler); if (shouldPass()) { - log.println("TEST PASSED"); + log.display("TEST PASSED"); return; } From fd9698357bb034c527c9ccdd6888a2abd75c0043 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 25 Aug 2026 03:57:20 +0000 Subject: [PATCH 062/223] 8390807: Reduce run time of test AOTCodeFlags.java Reviewed-by: kvn, asmehra --- .../cds/appcds/aotCode/AOTCodeFlags.java | 37 ++++++--------- .../appcds/aotCode/AOTCodeSimpleTestApp.java | 46 +++++++++++++++++++ 2 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeSimpleTestApp.java diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java index 966bacc3b143..d7ff823734ca 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,12 +31,9 @@ * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags JavacBenchApp + * @build AOTCodeFlags * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags */ /** @@ -48,12 +45,9 @@ * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags JavacBenchApp + * @build AOTCodeFlags * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Z */ /** @@ -65,12 +59,9 @@ * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags JavacBenchApp + * @build AOTCodeFlags * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Shenandoah */ /** @@ -82,12 +73,9 @@ * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags JavacBenchApp + * @build AOTCodeFlags * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Parallel */ @@ -98,6 +86,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class AOTCodeFlags { + private static String appName = AOTCodeSimpleTestApp.class.getName(); private static String gcName = null; public static void main(String... args) throws Exception { Tester t = new Tester(args.length == 0 ? null : args[0]); @@ -171,6 +160,10 @@ public String[] vmArgs(RunMode runMode) { args.addAll(List.of("-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug", "-Xlog:aot+codecache+stubs=debug")); + + // Ensure compilations are finished before the JVM exits. + args.add("-Xbatch"); + switch (runMode) { case RunMode.ASSEMBLY: args.addAll(getVMArgsForTestMode(aMode)); @@ -186,7 +179,7 @@ public String[] vmArgs(RunMode runMode) { @Override public String[] appCommandLine(RunMode runMode) { - return new String[] { "JavacBenchApp", "10" }; + return new String[] { appName }; } @Override diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeSimpleTestApp.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeSimpleTestApp.java new file mode 100644 index 000000000000..5debc6ab481c --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeSimpleTestApp.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Run long enough and with enough iterations to ensure C1 and C2 compilations. +// Note: run with -Xbatch to ensure compilations are finished before the JVM exits. +public class AOTCodeSimpleTestApp { + public static volatile int counter; + + public static void main(String args[]) { + long started = System.currentTimeMillis(); + + while (System.currentTimeMillis() - started < 150) { + outer(); + } + } + static void outer() { + for (int i = 0; i < 50 * 1000; i++) { + inner(); + } + } + + static void inner() { + counter++; + } +} From 9633dd75fee4b828e27ec8b4ea0ae8405698c4ef Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 25 Aug 2026 06:02:35 +0000 Subject: [PATCH 063/223] 8390620: Refactor eh_frame to frame in libsaproc Reviewed-by: cjplummer, sspitsyn --- .../linux/native/libsaproc/dwarf.cpp | 12 ++++++------ .../linux/native/libsaproc/dwarf.hpp | 2 +- .../linux/native/libsaproc/libproc_impl.c | 11 +++++------ .../linux/native/libsaproc/libproc_impl.h | 9 ++++----- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index bb7328379f02..f23ffce9a071 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -265,14 +265,14 @@ uint32_t DwarfParser::get_decoded_value(unsigned char enc) { // https://gcc.gnu.org/ml/gcc-help/2010-09/msg00166.html #if defined(_LP64) if (size == 8) { - result += _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result += _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); size = 4; } else #endif if ((enc & 0x70) == 0x10) { // 0x10 = DW_EH_PE_pcrel - result += _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result += _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); } else if (size == 2) { - result = static_cast(result) + _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result = static_cast(result) + _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); size = 4; } @@ -319,8 +319,8 @@ unsigned int DwarfParser::get_pc_range() { bool DwarfParser::process_dwarf(const uintptr_t pc) { // https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html - _buf = _lib->eh_frame.data; - unsigned char *end = _lib->eh_frame.data + _lib->eh_frame.size; + _buf = _lib->frame.data; + unsigned char *end = _lib->frame.data + _lib->frame.size; while (_buf <= end) { uint64_t length = get_entry_length(); if (length == 0L) { @@ -331,7 +331,7 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { uint32_t id = *(reinterpret_cast(_buf)); _buf += 4; if (id != 0) { // FDE - uintptr_t pc_begin = get_decoded_value(_fde_ptr_encoding) + _lib->eh_frame.library_base_addr; + uintptr_t pc_begin = get_decoded_value(_fde_ptr_encoding) + _lib->base; uintptr_t pc_end = pc_begin + get_pc_range(); if ((pc >= pc_begin) && (pc < pc_end)) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index 38ffaceb687e..110cd91ed4c4 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -108,7 +108,7 @@ class DwarfParser { } bool is_parseable() { - return _lib->eh_frame.data != NULL; + return _lib->frame.data != NULL; } }; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index 815902045cff..cc8f956bb0c1 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -128,7 +128,7 @@ static void destroy_lib_info(struct ps_prochandle* ph) { if (lib->symtab) { destroy_symtab(lib->symtab); } - free(lib->eh_frame.data); + free(lib->frame.data); free(lib); lib = next; } @@ -231,10 +231,9 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { for (cnt = 0, sh = shbuf; cnt < ehdr.e_shnum; cnt++, sh++) { if (strcmp(".eh_frame", sh->sh_name + strtab) == 0) { - lib->eh_frame.library_base_addr = lib->base; - lib->eh_frame.v_addr = sh->sh_addr; - lib->eh_frame.data = read_section_data(lib->fd, &ehdr, sh); - lib->eh_frame.size = sh->sh_size; + lib->frame.v_addr = sh->sh_addr; + lib->frame.data = read_section_data(lib->fd, &ehdr, sh); + lib->frame.size = sh->sh_size; break; } } @@ -242,7 +241,7 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { free(strtab); free(shbuf); lseek(lib->fd, current_pos, SEEK_SET); - return lib->eh_frame.data != NULL; + return lib->frame.data != NULL; } lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index d5aa74e73ad7..23d7daea9729 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -34,13 +34,12 @@ #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) -// .eh_frame data -typedef struct eh_frame_info { - uintptr_t library_base_addr; +// frame data +typedef struct frame_info { uintptr_t v_addr; unsigned char* data; int size; -} eh_frame_info; +} frame_info; // list of shared objects typedef struct lib_info { @@ -49,7 +48,7 @@ typedef struct lib_info { uintptr_t end; uintptr_t exec_start; uintptr_t exec_end; - eh_frame_info eh_frame; + frame_info frame; struct symtab* symtab; int fd; // file descriptor for lib struct lib_info* next; From 29fd00c069e106931771ade2f14ab2f0b9060567 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 25 Aug 2026 07:38:11 +0000 Subject: [PATCH 064/223] 8390641: C1/C2 on x86_64 - remove unused variables Reviewed-by: mchevalier, chagedorn --- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 5 +---- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 3 +-- src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 1 - src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 4 +--- src/hotspot/cpu/x86/c2_init_x86.cpp | 1 - src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp | 5 +---- src/hotspot/share/c1/c1_LIRGenerator.cpp | 3 +-- src/hotspot/share/c1/c1_RangeCheckElimination.cpp | 5 +---- 8 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 84f99215f156..7437de72bf1c 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -262,7 +262,6 @@ void LIR_Assembler::osr_entry() { // // build frame - ciMethod* m = compilation()->method(); __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); // OSR buffer is @@ -1339,7 +1338,6 @@ void LIR_Assembler::type_profile_helper(Register mdo, void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { // we always need a stub for the failure case. - CodeStub* stub = op->stub(); Register obj = op->object()->as_register(); Register k_RInfo = op->tmp1()->as_register(); Register klass_RInfo = op->tmp2()->as_register(); @@ -2341,7 +2339,7 @@ void LIR_Assembler::emit_static_call_stub() { return; } - int start = __ offset(); + DEBUG_ONLY(int start = __ offset();) // make sure that the displacement word of the call ends up word aligned __ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size_rex + NativeCall::displacement_offset); @@ -2937,7 +2935,6 @@ void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); int bci = op->profiled_bci(); - ciMethod* callee = op->profiled_callee(); Register tmp_load_klass = rscratch1; // Update counter for all call types diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 95de5906b62a..2642372bc373 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -674,7 +674,7 @@ LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_ } LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { - bool is_oop = is_reference_type(type); + DEBUG_ONLY(bool is_oop = is_reference_type(type);) LIR_Opr result = new_register(type); value.load_item(); // Because we want a 2-arg form of xchg and xadd @@ -920,7 +920,6 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { assert(UseCRC32Intrinsics, "need AVX and CLMUL instructions support"); // Make all state_for calls early since they can emit code LIR_Opr result = rlock_result(x); - int flags = 0; switch (x->id()) { case vmIntrinsics::_updateCRC32: { LIRItem crc(x->argument_at(0), this); diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index 20b6ee0a15ff..ecb997e878ac 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -814,7 +814,6 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { // for better readability - const bool must_gc_arguments = true; const bool dont_gc_arguments = false; // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 6e08f438a4af..a82067e95769 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -2243,7 +2243,6 @@ void C2_MacroAssembler::reduce16S(int opcode, Register dst, Register src1, XMMRe void C2_MacroAssembler::reduce32S(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) { assert_different_registers(src2, vtmp1); - int vector_len = Assembler::AVX_256bit; vextracti64x4_high(vtmp1, src2); reduce_operation_256(T_SHORT, opcode, vtmp1, vtmp1, src2); reduce16S(opcode, dst, src1, vtmp1, vtmp1, vtmp2); @@ -2507,7 +2506,6 @@ XMMRegister C2_MacroAssembler::get_lane(BasicType typ, XMMRegister dst, XMMRegis int esize = type2aelembytes(typ); int elem_per_lane = 16/esize; int lane = elemindex / elem_per_lane; - int eindex = elemindex % elem_per_lane; if (lane >= 2) { assert(UseAVX > 2, "required"); @@ -5188,7 +5186,7 @@ void C2_MacroAssembler::vector_castF2X_avx(BasicType to_elem_bt, XMMRegister dst void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2, AddressLiteral float_sign_flip, Register rscratch, int vec_enc) { - int to_elem_sz = type2aelembytes(to_elem_bt); + DEBUG_ONLY(int to_elem_sz = type2aelembytes(to_elem_bt);) assert(to_elem_sz <= 4, ""); vcvttps2dq(dst, src, vec_enc); vector_cast_fp_to_int_special_cases_evex(T_FLOAT, dst, src, xtmp1, xtmp2, ktmp1, ktmp2, rscratch, float_sign_flip, vec_enc); diff --git a/src/hotspot/cpu/x86/c2_init_x86.cpp b/src/hotspot/cpu/x86/c2_init_x86.cpp index 4d8db39bb0c5..0a74d0f7f3ac 100644 --- a/src/hotspot/cpu/x86/c2_init_x86.cpp +++ b/src/hotspot/cpu/x86/c2_init_x86.cpp @@ -36,7 +36,6 @@ void Compile::pd_compiler2_init() { if (UseAVX < 3) { int delta = XMMRegister::max_slots_per_register * XMMRegister::number_of_registers; int bottom = ConcreteRegisterImpl::max_fpr; - int top = bottom + delta; int middle = bottom + (delta / 2); int xmm_slots = XMMRegister::max_slots_per_register; int lower = xmm_slots / 2; diff --git a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp index b71fb46f0758..6585b60f8a0b 100644 --- a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp +++ b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp @@ -220,7 +220,7 @@ static void generate_string_indexof_stubs(StubGenerator *stubgen, address *fnptr assert(StubInfo::entry_count(stub_id) == 1, "sanity check"); GrowableArray
extras; - const int expected_extra_count = 2 * NUMBER_OF_CASES; + DEBUG_ONLY(const int expected_extra_count = 2 * NUMBER_OF_CASES;) address start = stubgen->load_archive_data(stub_id, nullptr, &extras); if (start != nullptr) { assert(extras.length() == expected_extra_count, @@ -1009,7 +1009,6 @@ static void broadcast_first_and_last_needle(Register needle, Register needle_len MacroAssembler *_masm) { bool isUL = (ae == StrIntrinsicNode::UL); bool isUU = (ae == StrIntrinsicNode::UU); - bool isU = (isUU || isUL); Label L_short; // Always need needle broadcast to ymm registers @@ -1776,8 +1775,6 @@ static void setup_jump_tables(StrIntrinsicNode::ArgEncoding ae, Label &L_error, bool isU = isUL || isUU; // At least one is UTF-16 const XMMRegister byte_1 = XMM_BYTE_1; - int jmp_ndx = 0; - //////////////////////////////////////////////// // On entry to each case, the register state is: // diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 19b4d9ae203c..a4e07cce619c 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -3097,7 +3097,6 @@ void LIRGenerator::do_Base(Base* x) { __ std_entry(LIR_OprFact::illegalOpr); // Emit moves from physical registers / stack slots to virtual registers CallingConvention* args = compilation()->frame_map()->incoming_arguments(); - IRScope* irScope = compilation()->hir()->top_scope(); int java_index = 0; for (int i = 0; i < args->length(); i++) { LIR_Opr src = args->at(i); @@ -3445,7 +3444,7 @@ void LIRGenerator::do_RuntimeCall(address routine, Intrinsic* x) { assert(x->number_of_arguments() == 0, "wrong type"); // Enforce computation of _reserved_argument_area_size which is required on some platforms. BasicTypeList signature; - CallingConvention* cc = frame_map()->c_calling_convention(&signature); + frame_map()->c_calling_convention(&signature); LIR_Opr reg = result_register_for(x->type()); __ call_runtime_leaf(routine, getThreadTemp(), reg, new LIR_OprList()); diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp index 1adf99cce61e..860a8c5470f3 100644 --- a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,6 @@ void RangeCheckEliminator::Visitor::do_LogicOp(LogicOp *lo) { void RangeCheckEliminator::Visitor::do_Phi(Phi *phi) { if (!phi->type()->as_IntType() && !phi->type()->as_ObjectType()) return; - BlockBegin *block = phi->block(); int op_count = phi->operand_count(); bool has_upper = true; bool has_lower = true; @@ -220,7 +219,6 @@ void RangeCheckEliminator::Visitor::do_ArithmeticOp(ArithmeticOp *ao) { if (ao->op() == Bytecodes::_irem) { Bound* x_bound = _rce->get_bound(x); - Bound* y_bound = _rce->get_bound(y); if (x_bound->lower() >= 0 && x_bound->lower_instr() == nullptr && y->as_ArrayLength() != nullptr) { _bound = new Bound(0, nullptr, -1, y); } else if (x_bound->has_lower() && x_bound->lower() >= 0 && y->type()->as_IntConstant() && @@ -872,7 +870,6 @@ void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, Block } // Lower instruction - Value index_instr = ai->index(); Value lower_instr = index_bound->lower_instr(); if (!loop_invariant(loop_header, lower_instr)) { TRACE_RANGE_CHECK_ELIMINATION( From bbfceab643bafdc5a4e661a1ae34bef0bf9c6215 Mon Sep 17 00:00:00 2001 From: Yunbo Zhang Date: Tue, 25 Aug 2026 08:33:29 +0000 Subject: [PATCH 065/223] 8369182: Don't force recompile of abstract_vm_version.cpp Reviewed-by: erikj, jwaters --- make/hotspot/lib/CompileJvm.gmk | 7 ------- 1 file changed, 7 deletions(-) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index bb67474b3a07..50b632a49f91 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -285,13 +285,6 @@ ifeq ($(call isTargetOs, windows), true) $(BUILD_LIBJVM_TARGET): $(WIN_EXPORT_FILE) endif -# Always recompile abstract_vm_version.cpp if libjvm needs to be relinked. This ensures -# that the internal vm version is updated as it relies on __DATE__ and __TIME__ -# macros. -ABSTRACT_VM_VERSION_OBJ := $(JVM_OUTPUTDIR)/objs/abstract_vm_version$(OBJ_SUFFIX) -$(ABSTRACT_VM_VERSION_OBJ): $(filter-out $(ABSTRACT_VM_VERSION_OBJ), \ - $(BUILD_LIBJVM_TARGET_DEPS)) - ifneq ($(GENERATE_COMPILE_COMMANDS_ONLY), true) ifeq ($(call isTargetOs, windows), true) # It doesn't matter which jvm.lib file gets exported, but we need From 05074deb7932247aca3ce38c47bf76163fa02901 Mon Sep 17 00:00:00 2001 From: Eric Fang Date: Tue, 25 Aug 2026 08:36:20 +0000 Subject: [PATCH 066/223] 8389666: C2: assert(false) failed: unexpected scalar opcode for integer DivV* Reviewed-by: qamai, xgong --- src/hotspot/share/opto/vectornode.cpp | 4 + .../TestVectorBroadcastTransforms.java | 97 ++++++++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 45ff6a7ffa24..4bc95eec13fc 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1281,6 +1281,10 @@ Node* VectorNode::make_scalar(Compile* c, int vopc, BasicType bt, Node* control, return new AndINode(in1, in2); case Op_AndL: return new AndLNode(in1, in2); + case Op_DivI: + return new DivINode(control, in1, in2); + case Op_DivL: + return new DivLNode(control, in1, in2); case Op_DivF: return new DivFNode(control, in1, in2); case Op_DivD: diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java index c58a6710c868..be4aeef23e34 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8358521 + * @bug 8358521 8389666 * @summary Optimize vector operations by reassociating broadcasted inputs * @modules jdk.incubator.vector * @library /test/lib / @@ -107,6 +107,41 @@ static void run_int_mul() { Verify.checkEQ(ir, ia * ib); } + // Integer vector DIV is currently matched on SVE. push_through_replicate + // must be able to scalarize DivVI via VectorNode::make_scalar(Op_DivI). + @Test + @IR(failOn = IRNode.DIV_VI, + applyIfCPUFeature = {"sve", "true"}, + counts = { IRNode.DIV_I, ">= 1", + IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) + static int int_div(int ia, int ib) { + return IntVector.broadcast(ISP, ia) + .lanewise(VectorOperators.DIV, IntVector.broadcast(ISP, ib)) + .lane(0); + } + + @Run(test = "int_div") + static void run_int_div() { + int ia = R.nextInt(); + int ib = R.nextInt(); + if (ib == 0) ib = 1; + int ir = int_div(ia, ib); + Verify.checkEQ(ir, ia / ib); + } + + // Minimal crash reproducer from VectorExpressionFuzzer (constant broadcasts). + @Test + static int int_div_broadcast_constants() { + return IntVector.broadcast(IntVector.SPECIES_128, -4096) + .div(IntVector.broadcast(IntVector.SPECIES_128, 1)) + .lane(0); + } + + @Run(test = "int_div_broadcast_constants") + static void run_int_div_broadcast_constants() { + Verify.checkEQ(int_div_broadcast_constants(), -4096); + } + @Test @IR(failOn = IRNode.AND_VI, applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, @@ -257,6 +292,26 @@ static void run_long_mul() { Verify.checkEQ(lr, la * lb); } + @Test + @IR(failOn = IRNode.DIV_VL, + applyIfCPUFeature = {"sve", "true"}, + counts = { IRNode.DIV_L, ">= 1", + IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) + static long long_div(long la, long lb) { + return LongVector.broadcast(LSP, la) + .div(LongVector.broadcast(LSP, lb)) + .lane(0); + } + + @Run(test = "long_div") + static void run_long_div() { + long la = R.nextLong(); + long lb = R.nextLong(); + if (lb == 0L) lb = 1L; + long lr = long_div(la, lb); + Verify.checkEQ(lr, la / lb); + } + @Test @IR(failOn = IRNode.AND_VL, applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, @@ -784,6 +839,26 @@ static void run_byte_mul() { Verify.checkEQ(br, (byte) (ba * bb)); } + @Test + @IR(failOn = IRNode.DIV_VB, + applyIfCPUFeature = {"sve", "true"}, + counts = { IRNode.DIV_I, ">= 1", + IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) + static byte byte_div(byte ba, byte bb) { + return ByteVector.broadcast(BSP, ba) + .div(ByteVector.broadcast(BSP, bb)) + .lane(0); + } + + @Run(test = "byte_div") + static void run_byte_div() { + byte ba = (byte) R.nextInt(); + byte bb = (byte) R.nextInt(); + if (bb == 0) bb = 1; + byte br = byte_div(ba, bb); + Verify.checkEQ(br, (byte) (ba / bb)); + } + @Test @IR(failOn = IRNode.AND_VB, applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, @@ -1007,6 +1082,26 @@ static void run_short_mul() { Verify.checkEQ(sr, (short) (sa * sb)); } + @Test + @IR(failOn = IRNode.DIV_VS, + applyIfCPUFeature = {"sve", "true"}, + counts = { IRNode.DIV_I, ">= 1", + IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) + static short short_div(short sa, short sb) { + return ShortVector.broadcast(SSP, sa) + .div(ShortVector.broadcast(SSP, sb)) + .lane(0); + } + + @Run(test = "short_div") + static void run_short_div() { + short sa = (short) R.nextInt(); + short sb = (short) R.nextInt(); + if (sb == 0) sb = 1; + short sr = short_div(sa, sb); + Verify.checkEQ(sr, (short) (sa / sb)); + } + @Test @IR(failOn = IRNode.AND_VS, applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, From f1e6f6d0625ba3e178a97ea7109510cd80a13b30 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 25 Aug 2026 09:00:44 +0000 Subject: [PATCH 067/223] 8390469: LogTest_large_message_vm_Test::TestBody crashes in case of low disc space Reviewed-by: iklam, jsjolen, lucy --- test/hotspot/gtest/logging/test_log.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/gtest/logging/test_log.cpp b/test/hotspot/gtest/logging/test_log.cpp index 871f2aa9bbef..2580bf8b78a8 100644 --- a/test/hotspot/gtest/logging/test_log.cpp +++ b/test/hotspot/gtest/logging/test_log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ TEST_VM_F(LogTest, large_message) { fclose(fp); size_t count = 0; + ASSERT_NE(nullptr, output); for (size_t ps = 0 ; output[ps + count] != '\0'; output[ps + count] == Xchar ? count++ : ps++); EXPECT_EQ(sizeof(big_msg) - 1, count); } From 51bb52c5c0a5a764dd080dc23bed0829fd0ae638 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 25 Aug 2026 09:41:11 +0000 Subject: [PATCH 068/223] 8391051: UnsafeAccessErrorHandshakeClosure should not be passed nullptr Reviewed-by: roland, sgehwolf --- src/hotspot/share/runtime/javaThread.inline.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index a5a3f9990cfb..293452ed9ccc 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -111,10 +111,14 @@ class UnsafeAccessErrorHandshakeClosure : public AsyncHandshakeClosure { public: UnsafeAccessErrorHandshakeClosure() : AsyncHandshakeClosure("UnsafeAccessErrorHandshakeClosure") {} void do_thread(Thread* thr) { + PRAGMA_DIAG_PUSH + PRAGMA_NONNULL_IGNORED + // Suppress GCC warning for nonnull as it doesn't recognize that `thr` is always the current thread. JavaThread* self = JavaThread::cast(thr); assert(self == JavaThread::current(), "must be"); self->handshake_state()->handle_unsafe_access_error(); + PRAGMA_DIAG_POP } bool is_async_exception() { return true; } }; From 6db3e26ea6a6d440e43ed705f21aace7d0b0bf30 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 25 Aug 2026 12:40:39 +0000 Subject: [PATCH 069/223] 8390929: G1: Uninitalized G1Policy::_to_collection_set_cards may cause unnecessary GC Reviewed-by: iwalulya, shade --- src/hotspot/share/gc/g1/g1Policy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index fc63a6e212a9..55bc3dccd54f 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -69,6 +69,7 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) : _young_gen_sizer(), _free_regions_at_end_of_collection(0), _pending_cards_from_gc(0), + _to_collection_set_cards(0), _collection_set(nullptr), _g1h(nullptr), _phase_times_timer(gc_timer), From 4f562fe39b83faf2c3dfdd8a1073aa01f7f03954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 25 Aug 2026 13:45:25 +0000 Subject: [PATCH 070/223] 8389880: Test: inlinetypes/DirectMethodTest.java needs to assert something Co-authored-by: Coleen Phillimore Reviewed-by: coleenp, cnorrbin, fparain --- .../inlinetypes/DirectMethodTest.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java index f4b6eb3634f4..b5b01a3786c2 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java @@ -31,7 +31,7 @@ * @library /test/lib * @enablePreview * @compile --source 28 DirectMethodTest.java - * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest + * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest flat */ /* @@ -44,7 +44,7 @@ * @library /test/lib * @enablePreview * @compile --source 28 DirectMethodTest.java - * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest + * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest noflat */ package runtime.valhalla.inlinetypes; @@ -52,20 +52,17 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; import jdk.internal.value.ValueClass; - +import jdk.test.lib.Asserts; public class DirectMethodTest { + static boolean expectFlat = false; public int method1(int i, int j, int k) { - System.out.println("i = " + i + " j = " + j + " k = " + k); return i + j * k; } - public static void printFlat(Object[] array) { - if (!ValueClass.isFlatArray(array)) { - System.out.println("not flat " + array); - } else { - System.out.println("yay flat " + array); - } + public static void checkFlat(Object[] array) { + boolean isFlat = ValueClass.isFlatArray(array); + Asserts.assertEquals(expectFlat, isFlat); } static value class SmallValue { @@ -76,30 +73,34 @@ static value class SmallValue { } public int method2(SmallValue i, SmallValue j, SmallValue k) { - System.out.println("i = " + i + " j = " + j + " k = " + k); return i.s + j.s * k.s; } static final int ARRAY_SIZE = 3; - public static void main(java.lang.String[] unused) throws Exception { + public static void main(String[] args) throws Exception { + expectFlat = args[0].equals("flat"); DirectMethodTest d = new DirectMethodTest(); Method m = DirectMethodTest.class.getMethod("method1", int.class, int.class, int.class); Integer[] intarray = new Integer[]{1, 2, 3}; // is this flattened? - printFlat(intarray); + checkFlat(intarray); Object[] array = (Object[])Array.newInstance(Integer.class, 3); - printFlat(array); + checkFlat(array); array = ValueClass.newNullableAtomicArray(Integer.class, ARRAY_SIZE); - printFlat(array); - System.out.println("value is " + m.invoke(d, 1, 2, 3)); + checkFlat(array); + if (!m.invoke(d, 1, 2, 3).equals(7)) { + throw new RuntimeException("Unexpected method1 result"); + } Method m2 = DirectMethodTest.class.getMethod("method2", SmallValue.class, SmallValue.class, SmallValue.class); Object[] smallValueArray = (Object[])Array.newInstance(SmallValue.class, ARRAY_SIZE); - printFlat(smallValueArray); + checkFlat(smallValueArray); smallValueArray = ValueClass.newNullableAtomicArray(SmallValue.class, ARRAY_SIZE); - printFlat(smallValueArray); - System.out.println("value is " + m2.invoke(d, new SmallValue((short)1), new SmallValue((short)2), new SmallValue((short)3))); + checkFlat(smallValueArray); + if (!m2.invoke(d, new SmallValue((short)1), new SmallValue((short)2), new SmallValue((short)3)).equals(7)) { + throw new RuntimeException("Unexpected method1 result"); + } } } From b0317e589eb7584f101ca5147267c54837872120 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 25 Aug 2026 14:42:01 +0000 Subject: [PATCH 071/223] 8389487: Test vmTestbase/nsk/jdi/ThreadReference/stop/stop002/TestDescription.java failed: unexpected com.sun.jdi.OpaqueFrameException Reviewed-by: sspitsyn, pchilanomate --- .../nsk/jdi/ThreadReference/stop/stop002.java | 36 ++++++++++++++----- .../jdi/ThreadReference/stop/stop002t.java | 16 +++++++-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002.java index 02a87d9c42b4..e52a7421383f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,15 +38,16 @@ * The test checks that the JDI method:
com.sun.jdi.ThreadReference.stop()
* behaves properly in various situations. It consists of 5 subtests. * - * TEST #1: Tests that stop() properly throws InvalidTypeException if - * specified throwable is not an instance of java.lang.Throwable in the target VM.

+ * TEST #1: Tests that stop() properly throws InvalidTypeException if + * specified throwable is not an instance of java.lang.Throwable in the target VM. * * TEST #2: Verify that stop() works when suspended at a breakpoint. * * TEST #3: Verify that stop() works when not suspended in a loop. For virtual threads * we expect an IncompatibleThreadStateException. * - * TEST #4: Verify that stop() works when suspended in a loop. + * TEST #4: Verify that stop() works when suspended in a loop. For Virtual threads + * we may get OpaqueFrameException. * * TEST #5: Verify that stop() works when suspended in Thread.sleep(). For virtual * threads we expect an OpaqueFrameException. @@ -65,9 +66,11 @@ public class stop002 { // debuggee fields used to indicate to exit infinite loops static final String DEBUGGEE_STOP_LOOP1_FIELD = "stopLooping1"; static final String DEBUGGEE_STOP_LOOP2_FIELD = "stopLooping2"; + // debuggee field used to indicate that debugger got OpaqueFrameException + static final String DEBUGGEE_GOT_OFE_FIELD = "gotOpaqueFrameException"; // debuggee source line where it should be stopped - static final int DEBUGGEE_STOPATLINE = 90; + static final int DEBUGGEE_STOPATLINE = 91; static final int DELAY = 500; // in milliseconds @@ -117,6 +120,7 @@ private int runIt(String args[], PrintStream out) { Field stopLoop1 = null; Field stopLoop2 = null; + Field gotOpaqueFrameException = null; ObjectReference objRef = null; ObjectReference throwableRef = null; @@ -143,6 +147,11 @@ private int runIt(String args[], PrintStream out) { throw new RuntimeException("Failed to find a \"stop loop\" field"); } + gotOpaqueFrameException = mainClass.fieldByName(DEBUGGEE_GOT_OFE_FIELD); + if (gotOpaqueFrameException == null) { + throw new RuntimeException("Failed to find a \"gotOpaqueFrameException\" field"); + } + log.display("non-throwable object: \"" + objRef + "\""); log.display("throwable object: \"" + throwableRef + "\""); log.display("debuggee thread: \"" + thrRef + "\""); @@ -205,8 +214,7 @@ private int runIt(String args[], PrintStream out) { tot_res = Consts.TEST_FAILED; } } finally { - // Force the debuggee out of the loop. Not really needed if the stop() call - // successfully threw the async exception, but it's easier to just always do this. + // Make sure the debuggee exits the loop even if the async exception was not thrown. log.display("TEST #3: clearing loop flag."); objRef.setValue(stopLoop1, vm.mirrorOf(true)); } @@ -222,15 +230,25 @@ private int runIt(String args[], PrintStream out) { log.display("TEST #4: thread is suspended."); thrRef.stop(throwableRef); log.display("TEST #4 PASSED: stop() call succeeded."); + objRef.setValue(gotOpaqueFrameException, vm.mirrorOf(false)); + } catch (OpaqueFrameException ofe) { + if (vthreadMode) { + log.display("TEST #4 PASSED: stop() call resulted in OpaqueFrameException while in vthread mode."); + } else { + ofe.printStackTrace(); + log.complain("TEST #4 FAILED: caught unexpected " + ofe); + tot_res = Consts.TEST_FAILED; + } + objRef.setValue(gotOpaqueFrameException, vm.mirrorOf(true)); } catch (Throwable ue) { ue.printStackTrace(); log.complain("TEST #4 FAILED: caught unexpected " + ue); tot_res = Consts.TEST_FAILED; + objRef.setValue(gotOpaqueFrameException, vm.mirrorOf(false)); } finally { log.display("TEST #4: resuming thread."); thrRef.resume(); - // Force the debuggee out of the loop. Not really needed if the stop() call - // successfully threw the async exception, but it's easier to just always do this. + // Make sure the debuggee exits the loop even if the async exception was not thrown. log.display("TEST #4: clearing loop flag."); objRef.setValue(stopLoop2, vm.mirrorOf(true)); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java index 0d87338f6781..2bfc82f9fac8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/stop/stop002t.java @@ -37,6 +37,7 @@ public class stop002t { private IOPipe pipe; volatile boolean stopLooping1 = false; volatile boolean stopLooping2 = false; + volatile boolean gotOpaqueFrameException = false; volatile static int testNumReady = 0; static final boolean vthreadMode = "Virtual".equals(System.getProperty("test.thread.factory")); static Thread testThread = null; @@ -139,8 +140,19 @@ private int runIt(String args[]) { testNumReady = 4; // signal debugger side of test that we are ready stopMeHere++; stopMeHere--; } - log.complain("TEST #4: Failed to throw expected exception"); - return Consts.TEST_FAILED; + if (vthreadMode) { + if (gotOpaqueFrameException) { + // Exception not required when in vthread mode if OpaqueFrameException thrown + log.display("TEST #4: threw OpaqueFrameException while in vthread mode"); + } else { + log.complain("TEST #4: Failed to throw expected exception and " + + "failed to throw debugger side OpaqueFrameException"); + return Consts.TEST_FAILED; + } + } else { + log.complain("TEST #4: Failed to throw expected exception"); + return Consts.TEST_FAILED; + } } catch (Throwable t) { // Call Thread.interrupted(). Workaround for JDK-8306324 log.display("TEST #4: interrupted = " + Thread.interrupted()); From a010948b97da4c2ec0d06541d1b67b52b1a65313 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 25 Aug 2026 15:10:09 +0000 Subject: [PATCH 072/223] 8390339: Test vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java timed out due to missing prompt with virtual threads Reviewed-by: sspitsyn, kevinw --- .../interrupt/interrupt001/interrupt001.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java index e090f357b4cd..5e8b57a4c6ec 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java @@ -105,6 +105,8 @@ protected void runCases() { Paragrep grep; String found; String[] threads; + String[] mainThreads; + String mainThread; jdb.setBreakpointInMethod(LAST_BREAK); waitForTestedThreadStarts(THREAD_STARTED_BREAK, numThreads); @@ -119,6 +121,23 @@ protected void runCases() { pauseTillAllThreadsWaiting(threads); + mainThreads = jdb.getThreadIdsByName("main"); + if (mainThreads.length != 1) { + log.complain("Failed to properly find one main thread: " + mainThreads.length); + success = false; + } + mainThread = mainThreads[0]; + + // Right now all threads are suspended. Before doing the interrupts we need to + // resume all threads except for the main thread. Otherwise, in the case of + // virtual threads, we can get a deadlock. To accomplish this we issue a + // "suspend" on the main thread so its suspend count is one higher than all + // the other threads, and then we "resume" on all threads, which should resume + // every thread except for the main thread. + reply = jdb.receiveReplyFor(JdbCommand.suspend + mainThread); + reply = jdb.receiveReplyFor(JdbCommand.resume, false); // don't expect a compound prompt + reply = jdb.receiveReplyFor(JdbCommand.thread + mainThread); // get compound prompt back + for (int i = 0; i < threads.length; i++) { reply = jdb.receiveReplyFor(JdbCommand.interrupt + threads[i]); } From aa8af37164be6072a496f9e4ddd00bfe8d9ef95a Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Tue, 25 Aug 2026 15:12:19 +0000 Subject: [PATCH 073/223] 8387729: Not all --long-options accept space as seperator Reviewed-by: alanb --- src/java.base/share/native/libjli/java.c | 30 +++++- .../TestEnableNativeAccess.java | 17 +++- .../java/lang/Object/FinalizationOption.java | 71 ++++++++++--- .../Object/InvalidFinalizationOption.java | 17 ++-- .../mutateFinals/cli/CommandLineTest.java | 99 +++++++++++++------ .../sun/misc/UnsafeMemoryAccessWarnings.java | 90 +++++++++++------ 6 files changed, 237 insertions(+), 87 deletions(-) diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index bf2d309e8e8f..30d281ded2fe 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -727,7 +727,8 @@ IsModuleOption(const char* name) { JLI_StrCmp(name, "--add-exports") == 0 || JLI_StrCmp(name, "--add-opens") == 0 || JLI_StrCmp(name, "--add-reads") == 0 || - JLI_StrCmp(name, "--patch-module") == 0; + JLI_StrCmp(name, "--patch-module") == 0 || + JLI_StrCmp(name, "--enable-final-field-mutation") == 0; } static jboolean @@ -739,7 +740,21 @@ IsLongFormModuleOption(const char* name) { JLI_StrCCmp(name, "--limit-modules=") == 0 || JLI_StrCCmp(name, "--add-exports=") == 0 || JLI_StrCCmp(name, "--add-reads=") == 0 || - JLI_StrCCmp(name, "--patch-module=") == 0; + JLI_StrCCmp(name, "--patch-module=") == 0 || + JLI_StrCCmp(name, "--enable-final-field-mutation=") == 0; +} + +/* + * Test if the given name is a non-module VM white-space option that + * will be passed to the VM with its corresponding long-form option + * name and "=" delimiter. + */ +static jboolean +IsNonModuleVMWhiteSpaceOption(const char* name) { + return JLI_StrCmp(name, "--illegal-native-access") == 0 || + JLI_StrCmp(name, "--illegal-final-field-mutation") == 0 || + JLI_StrCmp(name, "--sun-misc-unsafe-memory-access") == 0 || + JLI_StrCmp(name, "--finalization") == 0; } /* @@ -748,7 +763,8 @@ IsLongFormModuleOption(const char* name) { jboolean IsWhiteSpaceOption(const char* name) { return IsModuleOption(name) || - IsLauncherOption(name); + IsLauncherOption(name) || + IsNonModuleVMWhiteSpaceOption(name); } /* @@ -1125,7 +1141,7 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) { } kind = IsLauncherMainOption(arg) ? LAUNCHER_MAIN_OPTION : LAUNCHER_OPTION_WITH_ARGUMENT; - } else if (IsModuleOption(arg)) { + } else if (IsModuleOption(arg) || IsNonModuleVMWhiteSpaceOption(arg)) { kind = VM_LONG_OPTION_WITH_ARGUMENT; if (has_arg) { value = *argv; @@ -1239,6 +1255,12 @@ ParseArguments(int *pargc, char ***pargv, } else if (kind == VM_LONG_OPTION_WITH_ARGUMENT) { AddLongFormOption(option, value); } + /* + * Normalize a missing argument to the equivalent "--option=" form + * and let the subsequent option validation handle the empty value. + */ + } else if (!has_arg && IsNonModuleVMWhiteSpaceOption(arg)) { + AddLongFormOption(option, ""); /* * Error missing argument */ diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java index 6fc3f79260bf..b55664fd7431 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,7 @@ public Object[][] succeedCases() { { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"), new String[]{} }, { "panama_all_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, + { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access", "allow"} }, }; } @@ -137,7 +138,8 @@ public void testRepeatedOption() throws Exception { } /** - * Specifies bad value to --enable-native-access. + * Tests invalid values for --enable-native-access and invalid or missing + * values for --illegal-native-access. */ public void testBadValue() throws Exception { run("panama_deny_bad_unknown_module", PANAMA_MAIN, @@ -158,6 +160,17 @@ public void testBadValue() throws Exception { run("panama_deny_no_module_jni", PANAMA_JNI, failWithError("module panama_jni_load_module"), "--illegal-native-access=deny"); + run("panama_deny_no_module_jni", PANAMA_JNI, + failWithError("module panama_jni_load_module"), + "--illegal-native-access", "deny"); + // Missing value. + run("panama_enable_native_access", PANAMA_MAIN, + failWithError("Value specified to --illegal-native-access not recognized"), + "--illegal-native-access"); + // Invalid value. + run("panama_enable_native_access", PANAMA_MAIN, + failWithError("Value specified to --illegal-native-access not recognized"), + "--illegal-native-access", "bad"); } public void testDetailedWarningMessage() throws Exception { diff --git a/test/jdk/java/lang/Object/FinalizationOption.java b/test/jdk/java/lang/Object/FinalizationOption.java index 7d50412e26f0..bcd340209caa 100644 --- a/test/jdk/java/lang/Object/FinalizationOption.java +++ b/test/jdk/java/lang/Object/FinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,18 @@ /* * @test - * @bug 8276422 + * @bug 8276422 8387729 * @summary add command-line option to disable finalization - * @run main/othervm FinalizationOption yes - * @run main/othervm --finalization=enabled FinalizationOption yes - * @run main/othervm --finalization=disabled FinalizationOption no + * @library /test/lib + * @run main FinalizationOption enabled default + * @run main FinalizationOption enabled equals + * @run main FinalizationOption enabled whitespace + * @run main FinalizationOption disabled equals + * @run main FinalizationOption disabled whitespace */ + +import jdk.test.lib.process.ProcessTools; + public class FinalizationOption { static volatile boolean finalizerWasCalled = false; @@ -104,13 +110,54 @@ static boolean checkFinalizerCalled(boolean expected) { return passed; } - public static void main(String[] args) { - boolean finalizationEnabled = switch (args[0]) { - case "yes" -> true; - case "no" -> false; - default -> { - throw new AssertionError("usage: FinalizationOption yes|no"); - } + /* + * Each @run invocation enters main() twice: + * + * 1. jtreg invokes main() with two arguments. This calls launch() + * to start a test process. + * + * 2. The launched test process invokes main() with one argument and + * performs the actual test. + */ + public static void main(String[] args) throws Exception { + switch (args.length) { + case 2: + launch(args[0], args[1]); + return; + case 1: + test(args[0]); + return; + default: + throw new AssertionError( + "expected one or two arguments"); + } + } + + /** + * Launch a test process with the given command-line option form. + */ + static void launch(String option, String form) throws Exception { + String[] javaArgs = switch (form) { + case "default" -> new String[] {"FinalizationOption", option}; + case "equals" -> new String[] {"--finalization=" + option, + "FinalizationOption", option}; + case "whitespace" -> new String[] {"--finalization", option, + "FinalizationOption", option}; + default -> throw new AssertionError("Unexpected option form: " + form); + }; + + ProcessTools.executeTestJava(javaArgs).shouldHaveExitValue(0); + } + + /** + * Perform the actual finalization test. + */ + static void test(String option) throws Exception { + boolean finalizationEnabled = switch (option) { + case "enabled" -> true; + case "disabled" -> false; + default -> throw new AssertionError( + "usage: FinalizationOption enabled|disabled"); }; boolean threadPass = checkFinalizerThread(finalizationEnabled); diff --git a/test/jdk/java/lang/Object/InvalidFinalizationOption.java b/test/jdk/java/lang/Object/InvalidFinalizationOption.java index f87ecfe9045b..8dcaf153368b 100644 --- a/test/jdk/java/lang/Object/InvalidFinalizationOption.java +++ b/test/jdk/java/lang/Object/InvalidFinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8276422 + * @bug 8276422 8387729 * @summary Invalid/missing values for the finalization option should be rejected * @library /test/lib * @run driver InvalidFinalizationOption @@ -34,12 +34,17 @@ public class InvalidFinalizationOption { public static void main(String[] args) throws Exception { - record TestData(String arg, String expected) { } + record TestData(String[] arg, String expected) { } TestData[] testData = { - new TestData("--finalization", "Unrecognized option"), - new TestData("--finalization=", "Invalid finalization value"), - new TestData("--finalization=azerty", "Invalid finalization value") + new TestData(new String[] { "--finalization" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization=" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization=azerty" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization", "azerty" }, + "Invalid finalization value") }; for (var data : testData) { diff --git a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java index 34f9bb2bd5b0..00a854f06baa 100644 --- a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java +++ b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8353835 + * @bug 8353835 8387729 * @summary Test the command line option --enable-final-field-mutation * @library /test/lib * @build CommandLineTestHelper @@ -84,18 +84,27 @@ void testDefault() throws Exception { */ @Test void testAllow() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=allow") - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "allow")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldHaveExitValue(0); + } + + for (String[] opt : optionForms("--enable-final-field-mutation", "ALL-UNNAMED")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldHaveExitValue(0); + } - test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED") + // allow ALL-UNNAMED, deny by default + test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); - // allow ALL-UNNAMED, deny by default - test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") + test("testFieldSetInt", "--enable-final-field-mutation", "ALL-UNNAMED", "--illegal-final-field-mutation", "deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); @@ -122,12 +131,14 @@ void testAllow() throws Exception { */ @Test void testWarn() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=warn") - .shouldContain(WARNING_LINE1) - .shouldContain(WARNING_MUTATED) - .shouldContain(WARNING_LINE3) - .shouldContain(WARNING_LINE4) - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "warn")) { + test("testFieldSetInt", opt) + .shouldContain(WARNING_LINE1) + .shouldContain(WARNING_MUTATED) + .shouldContain(WARNING_LINE3) + .shouldContain(WARNING_LINE4) + .shouldHaveExitValue(0); + } test("testUnreflectSetter", "--illegal-final-field-mutation=warn") .shouldContain(WARNING_LINE1) @@ -162,13 +173,15 @@ void testWarn() throws Exception { */ @Test void testDebug() throws Exception { - test("testFieldSetInt+testUnreflectSetter", "--illegal-final-field-mutation=debug") - .shouldContain("Final field value in class " + HELPER) - .shouldContain(WARNING_MUTATED) - .shouldContain("java.lang.reflect.Field.setInt") - .shouldContain(WARNING_UNREFLECTED) - .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "debug")) { + test("testFieldSetInt+testUnreflectSetter", opt) + .shouldContain("Final field value in class " + HELPER) + .shouldContain(WARNING_MUTATED) + .shouldContain("java.lang.reflect.Field.setInt") + .shouldContain(WARNING_UNREFLECTED) + .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") + .shouldHaveExitValue(0); + } test("testUnreflectSetter+testFieldSetInt", "--illegal-final-field-mutation=debug") .shouldContain("Final field value in class " + HELPER) @@ -184,11 +197,13 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=deny") - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldContain("java.lang.IllegalAccessException") - .shouldNotHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "deny")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldContain("java.lang.IllegalAccessException") + .shouldNotHaveExitValue(0); + } test("testUnreflectSetter", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) @@ -202,7 +217,17 @@ void testDeny() throws Exception { */ @Test void testLastOneWins() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=allow", "--illegal-final-field-mutation=deny") + test("testFieldSetInt", + "--illegal-final-field-mutation=allow", + "--illegal-final-field-mutation=deny") + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldContain("java.lang.IllegalAccessException") + .shouldNotHaveExitValue(0); + + test("testFieldSetInt", + "--illegal-final-field-mutation", "allow", + "--illegal-final-field-mutation", "deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldContain("java.lang.IllegalAccessException") @@ -220,9 +245,11 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=" + value) - .shouldContain("Value specified to --illegal-final-field-mutation not recognized") - .shouldNotHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", value)) { + test("testFieldSetInt", opt) + .shouldContain("Value specified to --illegal-final-field-mutation not recognized") + .shouldNotHaveExitValue(0); + } } /** @@ -291,4 +318,14 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { private int countStrings(String input, String substring) { return input.split(Pattern.quote(substring)).length - 1; } + + /** + * Returns the given option in both supported argument forms. + */ + private String[][] optionForms(String option, String value) { + return new String[][] { + { option + "=" + value }, + { option, value } + }; + } } diff --git a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java index 0e71dfdc1940..f6ceb95c0cb2 100644 --- a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java +++ b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8331670 8338383 + * @bug 8331670 8338383 8387729 * @summary Basic test for --sun-misc-unsafe-memory-access= * @library /test/lib * @compile TryUnsafeMemoryAccess.java @@ -59,16 +59,17 @@ void testDefault(String input) throws Exception { */ @Test void testAllow() throws Exception { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", - "--sun-misc-unsafe-memory-access=allow") - .shouldHaveExitValue(0) - .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") - .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") - .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "allow")) { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") + .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + } } /** @@ -80,7 +81,9 @@ void testAllow() throws Exception { "objectFieldOffset+putLong+getLong" }) void testWarn(String input) throws Exception { - testOneWarning(input, "--sun-misc-unsafe-memory-access=warn"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "warn")) { + testOneWarning(input, opt); + } } /** @@ -113,15 +116,16 @@ private void testOneWarning(String input, String... vmopts) throws Exception { */ @Test void testDebug() throws Exception { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", - "--sun-misc-unsafe-memory-access=debug") - .shouldHaveExitValue(0) - .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") - .shouldContain("WARNING: sun.misc.Unsafe::putLong called") - .shouldContain("WARNING: sun.misc.Unsafe::getLong called") - .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "debug")) { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") + .shouldContain("WARNING: sun.misc.Unsafe::putLong called") + .shouldContain("WARNING: sun.misc.Unsafe::getLong called") + .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); + } } /** @@ -129,11 +133,13 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - test("allocateMemory+objectFieldOffset+invokeCleaner", "--sun-misc-unsafe-memory-access=deny") - .shouldHaveExitValue(0) - .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") - .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") - .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "deny")) { + test("allocateMemory+objectFieldOffset+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + } } /** @@ -171,8 +177,16 @@ void testInvokeReflectively() throws Exception { @Test void testLastOneWins() throws Exception { test("allocateMemory+objectFieldOffset+invokeCleaner", - "--sun-misc-unsafe-memory-access=allow", - "--sun-misc-unsafe-memory-access=deny") + "--sun-misc-unsafe-memory-access=allow", + "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + + test("allocateMemory+objectFieldOffset+invokeCleaner", + "--sun-misc-unsafe-memory-access", "allow", + "--sun-misc-unsafe-memory-access", "deny") .shouldHaveExitValue(0) .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") @@ -185,9 +199,11 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - test("allocateMemory", "--sun-misc-unsafe-memory-access=" + value) - .shouldNotHaveExitValue(0) - .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", value)) { + test("allocateMemory", opt) + .shouldNotHaveExitValue(0) + .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); + } } /** @@ -214,4 +230,14 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { .errorTo(System.err); return outputAnalyzer; } + + /** + * Returns the given option in both supported argument forms. + */ + private String[][] optionForms(String option, String value) { + return new String[][] { + { option + "=" + value }, + { option, value } + }; + } } From cd405e8b0381c4549afd6e96b21e27a9fe857f12 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 25 Aug 2026 16:15:29 +0000 Subject: [PATCH 074/223] 8390390: Shenandoah: ShenandoahAdaptiveInitialConfidence accepts negative values Reviewed-by: ruili, wkemper, kdnilsen, shade, xpeng --- src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index d76348b030aa..e57884548361 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -275,6 +275,7 @@ "margin of error for the average cycle time and average " \ "allocation rate. Increasing this value will cause the " \ "heuristic to initiate more concurrent cycles." ) \ + range(0.319,3.291) \ \ product(uintx, ShenandoahGuaranteedGCInterval, 5*60*1000, EXPERIMENTAL, \ "Many heuristics would guarantee a concurrent GC cycle at " \ From f06fb734fc04c2efb313a9eb2661d86298e1d478 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Tue, 25 Aug 2026 18:06:12 +0000 Subject: [PATCH 075/223] 8382276: Update nsk/jdwp to use ThreadWrapper Reviewed-by: dholmes, lmesnik --- .../nsk/jdwp/Event/BREAKPOINT/breakpoint001a.java | 11 ++++++----- .../nsk/jdwp/Event/EXCEPTION/exception001a.java | 11 ++++++----- .../nsk/jdwp/Event/FIELD_ACCESS/fldaccess001a.java | 9 +++++---- .../FIELD_MODIFICATION/fldmodification001a.java | 9 +++++---- .../nsk/jdwp/Event/METHOD_ENTRY/methentry001a.java | 9 +++++---- .../nsk/jdwp/Event/METHOD_EXIT/methexit001a.java | 9 +++++---- .../nsk/jdwp/Event/SINGLE_STEP/singlestep001a.java | 9 +++++---- .../nsk/jdwp/Event/SINGLE_STEP/singlestep002a.java | 9 +++++---- .../nsk/jdwp/Event/SINGLE_STEP/singlestep003a.java | 9 +++++---- .../nsk/jdwp/Event/THREAD_DEATH/thrdeath001a.java | 11 ++++++----- .../nsk/jdwp/Event/THREAD_START/thrstart001a.java | 11 ++++++----- .../MonitorInfo/monitorinfo001a.java | 5 ++++- .../jdwp/StackFrame/GetValues/getvalues001a.java | 9 +++++---- .../jdwp/StackFrame/PopFrames/popframes001a.java | 7 ++++--- .../jdwp/StackFrame/SetValues/setvalues001a.java | 5 ++++- .../jdwp/StackFrame/ThisObject/thisobject001a.java | 9 +++++---- .../CurrentContendedMonitor/curcontmonitor001a.java | 13 +++++++------ .../ThreadReference/FrameCount/framecnt001a.java | 5 ++++- .../nsk/jdwp/ThreadReference/Frames/frames001a.java | 9 +++++---- .../ThreadReference/Interrupt/interrupt001a.java | 9 +++++---- .../nsk/jdwp/ThreadReference/Name/name001a.java | 9 +++++---- .../OwnedMonitors/ownmonitors001a.java | 9 +++++---- .../nsk/jdwp/ThreadReference/Resume/resume001a.java | 9 +++++---- .../nsk/jdwp/ThreadReference/Status/status001a.java | 9 +++++---- .../nsk/jdwp/ThreadReference/Stop/stop001a.java | 5 ++++- .../jdwp/ThreadReference/Suspend/suspend001a.java | 9 +++++---- .../SuspendCount/suspendcnt001a.java | 9 +++++---- 27 files changed, 136 insertions(+), 101 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/BREAKPOINT/breakpoint001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/BREAKPOINT/breakpoint001a.java index 537c75014af1..342a3beeb010 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/BREAKPOINT/breakpoint001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/BREAKPOINT/breakpoint001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.BREAKPOINT; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,7 +37,7 @@ */ public class breakpoint001a { - static final int BREAKPOINT_LINE = 91; + static final int BREAKPOINT_LINE = 92; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -53,7 +54,7 @@ public int runIt(String args[], PrintStream out) { // create tested thread log.display("Creating tested thread"); - TestedClass.thread = new TestedClass(breakpoint001.TESTED_THREAD_NAME); + TestedClass.thread = new TestedClass(breakpoint001.TESTED_THREAD_NAME).getThread(); log.display(" ... thread created"); // start tested thread @@ -77,8 +78,8 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { - public static volatile TestedClass thread = null; + public static class TestedClass extends ThreadWrapper { + public static volatile Thread thread = null; public TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001a.java index eba8fe6e1dec..1422b149ff01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.EXCEPTION; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,9 +37,9 @@ */ public class exception001a { - static final int BREAKPOINT_LINE = 102; - static final int EXCEPTION_THROW_LINE = 114; - static final int EXCEPTION_CATCH_LINE = 121; // line number was changed due to 4740123 + static final int BREAKPOINT_LINE = 103; + static final int EXCEPTION_THROW_LINE = 115; + static final int EXCEPTION_CATCH_LINE = 122; // line number was changed due to 4740123 static ArgumentHandler argumentHandler = null; static Log log = null; @@ -84,7 +85,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { // static field with tested exception object public static volatile TestedExceptionClass exception = null; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_ACCESS/fldaccess001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_ACCESS/fldaccess001a.java index f027416d975f..c029973b990f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_ACCESS/fldaccess001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_ACCESS/fldaccess001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.FIELD_ACCESS; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class fldaccess001a { - static final int BREAKPOINT_LINE = 114; - static final int FIELD_ACCESS_LINE = 125; + static final int BREAKPOINT_LINE = 115; + static final int FIELD_ACCESS_LINE = 126; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -82,7 +83,7 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { public TestedThreadClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_MODIFICATION/fldmodification001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_MODIFICATION/fldmodification001a.java index 89ac3b882796..c78b61e72c18 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_MODIFICATION/fldmodification001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/FIELD_MODIFICATION/fldmodification001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.FIELD_MODIFICATION; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class fldmodification001a { - static final int BREAKPOINT_LINE = 114; - static final int FIELD_MODIFICATION_LINE = 126; + static final int BREAKPOINT_LINE = 115; + static final int FIELD_MODIFICATION_LINE = 127; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -82,7 +83,7 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { public TestedThreadClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_ENTRY/methentry001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_ENTRY/methentry001a.java index c231340f5325..49db5c5af99e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_ENTRY/methentry001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_ENTRY/methentry001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.METHOD_ENTRY; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class methentry001a { - static final int BREAKPOINT_LINE = 91; - static final int METHOD_ENTRY_LINE = 103; + static final int BREAKPOINT_LINE = 92; + static final int METHOD_ENTRY_LINE = 104; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -78,7 +79,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { public TestedClass(String name) { super(name); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_EXIT/methexit001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_EXIT/methexit001a.java index 4cd940f15d8e..469a0d9bd960 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_EXIT/methexit001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/METHOD_EXIT/methexit001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.METHOD_EXIT; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class methexit001a { - static final int BREAKPOINT_LINE = 91; - static final int METHOD_EXIT_LINE = 105; + static final int BREAKPOINT_LINE = 92; + static final int METHOD_EXIT_LINE = 106; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -78,7 +79,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { public TestedClass(String name) { super(name); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep001a.java index cf2937c5266e..5a87fc4431aa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.SINGLE_STEP; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class singlestep001a { - static final int BREAKPOINT_LINE = 91; - static final int SINGLE_STEP_LINE = 94; + static final int BREAKPOINT_LINE = 92; + static final int SINGLE_STEP_LINE = 95; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -78,7 +79,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { public TestedClass(String name) { super(name); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep002a.java index b79a8b0b322b..17e01ba8def1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.SINGLE_STEP; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class singlestep002a { - static final int BREAKPOINT_LINE = 91; - static final int SINGLE_STEP_LINE = 101; + static final int BREAKPOINT_LINE = 92; + static final int SINGLE_STEP_LINE = 102; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -78,7 +79,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { public TestedClass(String name) { super(name); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep003a.java index 164db266ce7b..617c51e4e897 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/SINGLE_STEP/singlestep003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.SINGLE_STEP; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,8 +37,8 @@ */ public class singlestep003a { - static final int BREAKPOINT_LINE = 101; - static final int SINGLE_STEP_LINE = 92; + static final int BREAKPOINT_LINE = 102; + static final int SINGLE_STEP_LINE = 93; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -78,7 +79,7 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { public TestedClass(String name) { super(name); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_DEATH/thrdeath001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_DEATH/thrdeath001a.java index 140ae1257f62..1f092ea052f9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_DEATH/thrdeath001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_DEATH/thrdeath001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.THREAD_DEATH; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,7 +37,7 @@ */ public class thrdeath001a { - static final int BREAKPOINT_LINE = 93; + static final int BREAKPOINT_LINE = 94; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -53,7 +54,7 @@ public int runIt(String args[], PrintStream out) { // create tested thread log.display("Creating tested thread"); - TestedClass.thread = new TestedClass(thrdeath001.TESTED_THREAD_NAME); + TestedClass.thread = new TestedClass(thrdeath001.TESTED_THREAD_NAME).getThread(); log.display(" ... thread created"); // reach breakpoint @@ -80,8 +81,8 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { - public static volatile TestedClass thread = null; + public static class TestedClass extends ThreadWrapper { + public static volatile Thread thread = null; public TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_START/thrstart001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_START/thrstart001a.java index 674a49d942b9..c5d44df6924c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_START/thrstart001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/THREAD_START/thrstart001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.Event.THREAD_START; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -36,7 +37,7 @@ */ public class thrstart001a { - static final int BREAKPOINT_LINE = 93; + static final int BREAKPOINT_LINE = 94; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -53,7 +54,7 @@ public int runIt(String args[], PrintStream out) { // create tested thread log.display("Creating tested thread"); - TestedClass.thread = new TestedClass(thrstart001.TESTED_THREAD_NAME); + TestedClass.thread = new TestedClass(thrstart001.TESTED_THREAD_NAME).getThread(); log.display(" ... thread created"); // reach breakpoint @@ -80,8 +81,8 @@ public int runIt(String args[], PrintStream out) { } // tested class - public static class TestedClass extends Thread { - public static volatile TestedClass thread = null; + public static class TestedClass extends ThreadWrapper { + public static volatile Thread thread = null; public TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/MonitorInfo/monitorinfo001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/MonitorInfo/monitorinfo001a.java index fa0386cfa5db..b7e528be32e6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/MonitorInfo/monitorinfo001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/MonitorInfo/monitorinfo001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -215,6 +215,9 @@ public TestedClass() { } // TestedClass class // thread which will owns monitor of the tested object + // Note: the monitor threads must extend Thread, not ThreadWrapper. JDWP + // ObjectReference.MonitorInfo reports no owner and no waiters when virtual + // threads own or wait on the monitor. See JDK-8382276. public static class MonitorOwnerThread extends Thread { public Object ready = new Object(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/GetValues/getvalues001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/GetValues/getvalues001a.java index d2bef481384c..66f2431e0e71 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/GetValues/getvalues001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/GetValues/getvalues001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.StackFrame.GetValues; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -74,7 +75,7 @@ public int runIt(String args[], PrintStream out) { log.display("Creating object of tested class"); TestedObjectClass.object = new TestedObjectClass(); log.display("Creating tested thread"); - TestedObjectClass.thread = new TestedThreadClass(THREAD_NAME); + TestedObjectClass.thread = new TestedThreadClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadReady) { @@ -123,7 +124,7 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { TestedThreadClass(String name) { super(name); @@ -144,7 +145,7 @@ public void run() { public static class TestedObjectClass { // field with the tested thread and object values - public static volatile TestedThreadClass thread = null; + public static volatile Thread thread = null; public static volatile TestedObjectClass object = null; public void testedMethod() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/PopFrames/popframes001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/PopFrames/popframes001a.java index 20bb707b14f6..cfe1a919bf93 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/PopFrames/popframes001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/PopFrames/popframes001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package nsk.jdwp.StackFrame.PopFrames; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -40,7 +41,7 @@ public class popframes001a { public static final String THREAD_NAME = "testedThread"; // line nunber for breakpoint - public static final int BREAKPOINT_LINE_NUMBER = 113; + public static final int BREAKPOINT_LINE_NUMBER = 114; // scaffold objects private static volatile ArgumentHandler argumentHandler = null; @@ -82,7 +83,7 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { // number of invokations of tested method public static volatile int invokations = 0; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/SetValues/setvalues001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/SetValues/setvalues001a.java index 81c9a51b1cfc..27b4fd6d57f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/SetValues/setvalues001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/SetValues/setvalues001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,6 +158,9 @@ public int runIt(String args[], PrintStream out) { } // tested thread class + // Note: TestedThreadClass must extend Thread, not ThreadWrapper. JDWP + // StackFrame.SetValues returns OPAQUE_FRAME for a virtual thread suspended + // with ThreadReference.Suspend rather than at an event. See JDK-8382276. public static class TestedThreadClass extends Thread { public TestedThreadClass(String name) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/ThisObject/thisobject001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/ThisObject/thisobject001a.java index 42bb065994bc..81662743780f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/ThisObject/thisobject001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/StackFrame/ThisObject/thisobject001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.StackFrame.ThisObject; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -73,7 +74,7 @@ public int runIt(String args[], PrintStream out) { log.display("Creating object of tested class"); TestedObjectClass.object = new TestedObjectClass(); log.display("Creating tested thread"); - TestedObjectClass.thread = new TestedThreadClass(THREAD_NAME); + TestedObjectClass.thread = new TestedThreadClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadReady) { @@ -122,7 +123,7 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedThreadClass extends Thread { + public static class TestedThreadClass extends ThreadWrapper { TestedThreadClass(String name) { super(name); @@ -144,7 +145,7 @@ public void run() { public static class TestedObjectClass { // field with the tested thread and object values - public static volatile TestedThreadClass thread = null; + public static volatile Thread thread = null; public static volatile TestedObjectClass object = null; public void testedMethod(int foo) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java index 1f20c1c70414..ccd9f7d52080 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.CurrentContendedMonitor; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -69,7 +70,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarting) { @@ -84,8 +85,8 @@ public int runIt(String args[], PrintStream out) { } // ensure that tested thread is waiting for monitor object - synchronized (TestedClass.thread.monitor) { - TestedClass.thread.monitor.notifyAll(); + synchronized (TestedClass.monitor) { + TestedClass.monitor.notifyAll(); // send debugger signal READY log.display("Sending signal to debugger: " + curcontmonitor001.READY); @@ -112,10 +113,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; // field with monitor object which thread will infinitively wait for public static volatile Object monitor = new Object(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/FrameCount/framecnt001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/FrameCount/framecnt001a.java index eba135fe2b45..530c2f1f0d7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/FrameCount/framecnt001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/FrameCount/framecnt001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,9 @@ public int runIt(String args[], PrintStream out) { } // tested thread class + // Note: TestedClass must extend Thread, not ThreadWrapper. This test + // asserts an exact frame count, which the wrapper's extra frames change. + // See JDK-8382276. public static class TestedClass extends Thread { // field with the tested Thread value diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Frames/frames001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Frames/frames001a.java index d106259c431f..951d40a9bf12 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Frames/frames001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Frames/frames001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Frames; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -70,7 +71,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadReady) { @@ -108,10 +109,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; int frames = 0; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Interrupt/interrupt001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Interrupt/interrupt001a.java index 7677411b7d84..000b91a929d2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Interrupt/interrupt001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Interrupt/interrupt001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Interrupt; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarting) { @@ -139,10 +140,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Name/name001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Name/name001a.java index de88acecf519..0cc160a56699 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Name/name001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Name/name001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Name; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarted) { @@ -104,10 +105,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/OwnedMonitors/ownmonitors001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/OwnedMonitors/ownmonitors001a.java index 0f929bcdac44..0be2457496bc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/OwnedMonitors/ownmonitors001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/OwnedMonitors/ownmonitors001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.OwnedMonitors; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -68,7 +69,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadReady) { @@ -106,10 +107,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; // field with object whose monitor the tested thread owns public static Object ownedMonitor = new Object(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Resume/resume001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Resume/resume001a.java index 689e7693021c..9517ec28285c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Resume/resume001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Resume/resume001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Resume; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarted) { @@ -104,10 +105,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Status/status001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Status/status001a.java index 1429a7e4a75a..c3589bcf326e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Status/status001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Status/status001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Status; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarted) { @@ -104,10 +105,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Stop/stop001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Stop/stop001a.java index f046041276ca..30f2d41eaaaa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Stop/stop001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Stop/stop001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,6 +144,9 @@ public int runIt(String args[], PrintStream out) { } // tested thread class + // Note: TestedClass must extend Thread, not ThreadWrapper. JDWP + // ThreadReference.Stop returns THREAD_NOT_SUSPENDED for a virtual thread + // that is not suspended at an event. See JDK-8382276. public static class TestedClass extends Thread { // field with the tested Thread value diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Suspend/suspend001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Suspend/suspend001a.java index eced97136d62..fd3da5283915 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Suspend/suspend001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/Suspend/suspend001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.Suspend; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarted) { @@ -104,10 +105,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/SuspendCount/suspendcnt001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/SuspendCount/suspendcnt001a.java index 5c6d77b1b8a3..5a9b4d025ebd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/SuspendCount/suspendcnt001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/SuspendCount/suspendcnt001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.jdwp.ThreadReference.SuspendCount; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jpda.*; import nsk.share.jdwp.*; @@ -66,7 +67,7 @@ public int runIt(String args[], PrintStream out) { // load tested class and create tested thread log.display("Creating object of tested class"); - TestedClass.thread = new TestedClass(THREAD_NAME); + TestedClass.thread = new TestedClass(THREAD_NAME).getThread(); // start the thread and wait for notification from it synchronized (threadStarted) { @@ -104,10 +105,10 @@ public int runIt(String args[], PrintStream out) { } // tested thread class - public static class TestedClass extends Thread { + public static class TestedClass extends ThreadWrapper { // field with the tested Thread value - public static volatile TestedClass thread = null; + public static volatile Thread thread = null; TestedClass(String name) { super(name); From f40a2c3625484087cfdb41d34b360414ccf0ebd0 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Tue, 25 Aug 2026 18:06:46 +0000 Subject: [PATCH 076/223] 8241634: Support execution of threads as virtual in LingeredApp Reviewed-by: cjplummer, lmesnik --- test/hotspot/jtreg/ProblemList-Virtual.txt | 1 + .../vthread/HeapDump/VThreadInHeapDump.java | 5 ++-- test/lib/jdk/test/lib/apps/LingeredApp.java | 24 ++++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 53bb850a6ecc..4a6349555114 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -27,6 +27,7 @@ runtime/jni/critical/SuspendInCritical.java 8384369 generic-all serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java 8308026 generic-all serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java 8264699 generic-all +serviceability/sa/TestHeapDumpForInvokeDynamic.java 8390689 generic-all vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all vmTestbase/nsk/jvmti/unit/functions/Dispose/JvmtiTest/TestDescription.java 8387429 generic-all diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java index de64706a8967..441f63d9246b 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,7 +152,8 @@ private void runTest(String[] args) { pthread.waitReady(); // We are ready. - LingeredApp.main(args); + // Run the app on the current thread, the scheduler is limited to one carrier. + LingeredApp.mainLoop(args); } finally { // Signal all threads to finish. diff --git a/test/lib/jdk/test/lib/apps/LingeredApp.java b/test/lib/jdk/test/lib/apps/LingeredApp.java index f8ebc844bcb5..4e53018bf95f 100644 --- a/test/lib/jdk/test/lib/apps/LingeredApp.java +++ b/test/lib/jdk/test/lib/apps/LingeredApp.java @@ -331,6 +331,11 @@ private List runAppPrepare(String[] vmArguments) { String classpath = System.getProperty("test.class.path"); cmd.add((classpath == null) ? "." : classpath); } + // Forward test.thread.factory to child process for virtual thread testing + String testThreadFactory = System.getProperty("test.thread.factory"); + if (testThreadFactory != null) { + cmd.add("-Dtest.thread.factory=" + testThreadFactory); + } return cmd; } @@ -609,8 +614,25 @@ protected static boolean isReady() { */ @SuppressWarnings("restricted") public static void main(String args[]) { - boolean forceCrash = false; + // Checks the property directly so the app keeps working with a minimal classpath. + if ("Virtual".equals(System.getProperty("test.thread.factory"))) { + Thread t = Thread.ofVirtual().start(() -> mainLoop(args)); + try { + t.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } else { + mainLoop(args); + } + } + /** + * Runs the app on the current thread regardless of the test thread factory. + */ + @SuppressWarnings("restricted") + public static void mainLoop(String[] args) { + boolean forceCrash = false; if (args.length == 0) { System.err.println("Lock file name is not specified"); System.exit(7); From 660dd42d7a5ceb863f2199552db530b6c20238fe Mon Sep 17 00:00:00 2001 From: Chuanqi Zang Date: Wed, 26 Aug 2026 02:08:59 +0000 Subject: [PATCH 077/223] 8391041: RISC-V: Fix out-of-bounds read in string_indexof_char intrinsic Reviewed-by: dzhang, fyang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 64 ++++++++++++------- .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 1 + 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index c0504ba23da7..7725b2dfca51 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -408,6 +408,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, // StringLatin1.indexOfChar void C2_MacroAssembler::string_indexof_char_short(Register str1, Register cnt1, Register ch, Register result, + Register start_index, bool isL) { Register ch1 = t0; @@ -500,7 +501,7 @@ void C2_MacroAssembler::string_indexof_char_short(Register str1, Register cnt1, addi(index, index, 7); bind(MATCH); - mv(result, index); + add(result, start_index, index); bind(NOMATCH); BLOCK_COMMENT("} string_indexof_char_short"); } @@ -513,39 +514,39 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register tmp3, Register tmp4, bool isL) { - Label CH1_LOOP, HIT, NOMATCH, DONE, DO_LONG; + Label CH1_LOOP, HIT, NOMATCH, DONE, SHORT; Register ch1 = t0; Register orig_cnt = t1; Register mask1 = tmp3; Register mask2 = tmp2; Register match_mask = tmp1; - Register trailing_char = tmp4; - Register unaligned_elems = tmp4; + Register loop_step = tmp4; + Register trailing_chars = tmp4; + Register unaligned_chars = tmp4; + Register start_index = tmp4; BLOCK_COMMENT("string_indexof_char {"); beqz(cnt1, NOMATCH); subi(t0, cnt1, isL ? 32 : 16); - bgtz(t0, DO_LONG); - string_indexof_char_short(str1, cnt1, ch, result, isL); - j(DONE); + mv(start_index, zr); + blez(t0, SHORT); - bind(DO_LONG); mv(orig_cnt, cnt1); if (AvoidUnalignedAccesses) { Label ALIGNED; - andi(unaligned_elems, str1, 0x7); - beqz(unaligned_elems, ALIGNED); - sub(unaligned_elems, unaligned_elems, 8); - neg(unaligned_elems, unaligned_elems); + andi(unaligned_chars, str1, 0x7); + beqz(unaligned_chars, ALIGNED); + sub(unaligned_chars, unaligned_chars, 8); + neg(unaligned_chars, unaligned_chars); if (!isL) { - srli(unaligned_elems, unaligned_elems, 1); + srli(unaligned_chars, unaligned_chars, 1); } // do unaligned part per element - string_indexof_char_short(str1, unaligned_elems, ch, result, isL); + string_indexof_char_short(str1, unaligned_chars, ch, result, zr, isL); bgez(result, DONE); mv(orig_cnt, cnt1); - sub(cnt1, cnt1, unaligned_elems); + sub(cnt1, cnt1, unaligned_chars); bind(ALIGNED); } @@ -570,29 +571,48 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, uint64_t mask7fff = UCONST64(0x7fff7fff7fff7fff); mv(mask2, isL ? mask7f7f : mask7fff); + mv(loop_step, 8); + bind(CH1_LOOP); ld(ch1, Address(str1)); addi(str1, str1, 8); subi(cnt1, cnt1, 8); compute_match_mask(ch1, ch, match_mask, mask1, mask2); bnez(match_mask, HIT); - bgtz(cnt1, CH1_LOOP); - j(NOMATCH); + bge(cnt1, loop_step, CH1_LOOP); + + beqz(cnt1, NOMATCH); + if (!isL) { + srli(cnt1, cnt1, 1); + } + // Tail (1..7 chars) after the SWAR loop has advanced str1. cnt1 holds the + // remaining char count; the number of chars already scanned by the loop is + // (orig_cnt - cnt1). string_indexof_char_short returns an index relative to + // the current str1, so we pass that prefix as start_index to recover the + // real index. + // Note: ch was broadcast across all 8 bytes for the SWAR loop above, but the + // short helper compares a single element, so restore ch to a single char. + isL ? zext(ch, ch, 8) : zext(ch, ch, 16); + sub(start_index, orig_cnt, cnt1); + + bind(SHORT); + string_indexof_char_short(str1, cnt1, ch, result, start_index, isL); + j(DONE); bind(HIT); // count bits of trailing zero chars - ctzc_bits(trailing_char, match_mask, isL, ch1, result); - srli(trailing_char, trailing_char, 3); + ctzc_bits(trailing_chars, match_mask, isL, ch1, result); + srli(trailing_chars, trailing_chars, 3); addi(cnt1, cnt1, 8); - ble(cnt1, trailing_char, NOMATCH); + // match case if (!isL) { srli(cnt1, cnt1, 1); - srli(trailing_char, trailing_char, 1); + srli(trailing_chars, trailing_chars, 1); } sub(result, orig_cnt, cnt1); - add(result, result, trailing_char); + add(result, result, trailing_chars); j(DONE); bind(NOMATCH); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index db80d048e927..8fea474dacb2 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -64,6 +64,7 @@ void string_indexof_char_short(Register str1, Register cnt1, Register ch, Register result, + Register start_index, bool isL); void string_indexof_char(Register str1, Register cnt1, From 393c3a028ea6a88b90eaa2aee4f8ccf896aa1a4c Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 26 Aug 2026 05:28:41 +0000 Subject: [PATCH 078/223] 8390826: RISC-V: Use dedicated vector mask logical instructions Reviewed-by: fyang, gcao --- src/hotspot/cpu/riscv/riscv_v.ad | 132 ++++++++++- .../compiler/lib/ir_framework/IRNode.java | 50 ++++ .../AllBitsSetVectorMatchRuleTest.java | 154 +++++++++++++ .../vector/MaskLogicOperationsBenchmark.java | 214 +++++++++++++++++- 4 files changed, 548 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index ef0ce89133ed..a4cd5c838715 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -4518,7 +4518,7 @@ instruct vmaskAllL(vRegMask dst, iRegL src) %{ // ------------------------------ Vector mask basic OPs ------------------------ -// vector mask logical ops: and/and-not/or/xor +// vector mask logical ops instruct vmask_and(vRegMask dst, vRegMask src1, vRegMask src2) %{ match(Set dst (AndVMask src1 src2)); @@ -4559,6 +4559,136 @@ instruct vmask_and_notL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) ins_pipe(pipe_slow); %} +instruct vmask_or_notI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{ + match(Set dst (OrVMask src1 (XorVMask src2 (MaskAll m1)))); + format %{ "vmask_or_notI $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmorn_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_or_notL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{ + match(Set dst (OrVMask src1 (XorVMask src2 (MaskAll m1)))); + format %{ "vmask_or_notL $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmorn_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_nandI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{ + match(Set dst (XorVMask (AndVMask src1 src2) (MaskAll m1))); + format %{ "vmask_nandI $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnand_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_nandL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{ + match(Set dst (XorVMask (AndVMask src1 src2) (MaskAll m1))); + format %{ "vmask_nandL $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnand_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_norI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{ + match(Set dst (XorVMask (OrVMask src1 src2) (MaskAll m1))); + format %{ "vmask_norI $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnor_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_norL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{ + match(Set dst (XorVMask (OrVMask src1 src2) (MaskAll m1))); + format %{ "vmask_norL $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnor_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_xnorI(vRegMask dst, vRegMask src1, vRegMask src2, immI_M1 m1) %{ + match(Set dst (XorVMask (XorVMask src1 src2) (MaskAll m1))); + match(Set dst (XorVMask src1 (XorVMask src2 (MaskAll m1)))); + format %{ "vmask_xnorI $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmxnor_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_xnorL(vRegMask dst, vRegMask src1, vRegMask src2, immL_M1 m1) %{ + match(Set dst (XorVMask (XorVMask src1 src2) (MaskAll m1))); + match(Set dst (XorVMask src1 (XorVMask src2 (MaskAll m1)))); + format %{ "vmask_xnorL $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmxnor_mm(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_notI(vRegMask dst, vRegMask src, immI_M1 m1) %{ + match(Set dst (XorVMask src (MaskAll m1))); + format %{ "vmask_notI $dst, $src" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnot_m(as_VectorRegister($dst$$reg), + as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmask_notL(vRegMask dst, vRegMask src, immL_M1 m1) %{ + match(Set dst (XorVMask src (MaskAll m1))); + format %{ "vmask_notL $dst, $src" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmnot_m(as_VectorRegister($dst$$reg), + as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vmask_or(vRegMask dst, vRegMask src1, vRegMask src2) %{ match(Set dst (OrVMask src1 src2)); format %{ "vmask_or $dst, $src1, $src2" %} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 6fad572fd37f..a59331a9239d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2808,6 +2808,56 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) machOnlyNameRegex(VMASK_AND_NOT_L, "vmask_and_notL"); } + public static final String RISCV_VMASK_OR_NOT_I = PREFIX + "RISCV_VMASK_OR_NOT_I" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_OR_NOT_I, "vmask_or_notI"); + } + + public static final String RISCV_VMASK_OR_NOT_L = PREFIX + "RISCV_VMASK_OR_NOT_L" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_OR_NOT_L, "vmask_or_notL"); + } + + public static final String RISCV_VMASK_NAND_I = PREFIX + "RISCV_VMASK_NAND_I" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NAND_I, "vmask_nandI"); + } + + public static final String RISCV_VMASK_NAND_L = PREFIX + "RISCV_VMASK_NAND_L" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NAND_L, "vmask_nandL"); + } + + public static final String RISCV_VMASK_NOR_I = PREFIX + "RISCV_VMASK_NOR_I" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NOR_I, "vmask_norI"); + } + + public static final String RISCV_VMASK_NOR_L = PREFIX + "RISCV_VMASK_NOR_L" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NOR_L, "vmask_norL"); + } + + public static final String RISCV_VMASK_XNOR_I = PREFIX + "RISCV_VMASK_XNOR_I" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_XNOR_I, "vmask_xnorI"); + } + + public static final String RISCV_VMASK_XNOR_L = PREFIX + "RISCV_VMASK_XNOR_L" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_XNOR_L, "vmask_xnorL"); + } + + public static final String RISCV_VMASK_NOT_I = PREFIX + "RISCV_VMASK_NOT_I" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NOT_I, "vmask_notI"); + } + + public static final String RISCV_VMASK_NOT_L = PREFIX + "RISCV_VMASK_NOT_L" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VMASK_NOT_L, "vmask_notL"); + } + public static final String VMLA = PREFIX + "VMLA" + POSTFIX; static { machOnlyNameRegex(VMLA, "vmla"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java index b95771d98629..a88c7d5c36ef 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java @@ -240,6 +240,160 @@ public static void testMaskAndNotL() { } } + @Test + @IR(counts = { IRNode.RISCV_VMASK_NOT_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNotI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + avm.not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(!ma[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_NOT_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNotL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + avm.not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(!ma[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_NAND_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNandI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.and(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] & mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_NAND_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNandL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.and(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] & mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_NOR_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNorI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.or(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] | mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_NOR_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskNorL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.or(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] | mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_XNOR_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskXnorI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.xor(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] ^ mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_XNOR_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskXnorL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.xor(bvm).not().intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(!(ma[i] ^ mb[i]), mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_XNOR_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskEqI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.eq(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(ma[i] == mb[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_XNOR_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskEqL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.eq(bvm).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(ma[i] == mb[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_OR_NOT_I, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskOrNotI() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(I_SPECIES, mb, 0); + avm.or(bvm.not()).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals(ma[i] | !mb[i], mr[i]); + } + } + + @Test + @IR(counts = { IRNode.RISCV_VMASK_OR_NOT_L, "1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testMaskOrNotL() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); + avm.or(bvm.not()).intoArray(mr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals(ma[i] | !mb[i], mr[i]); + } + } + // Tests that mask.not().and(other) matches to VMASK_AND_NOT (AndVMask commutative rule). @Test @IR(counts = { IRNode.VMASK_AND_NOT_I, "1" }, applyIfCPUFeatureOr = {"sve", "true", "rvv", "true"}) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java index b70588906af9..9a3d6319df94 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskLogicOperationsBenchmark.java @@ -98,6 +98,218 @@ public void longMaskAndNot() { } } + @Benchmark + public void byteMaskNot() { + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm = VectorMask.fromArray(B_SPECIES, ma, i); + vm.not().intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskNot() { + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm = VectorMask.fromArray(S_SPECIES, ma, i); + vm.not().intoArray(mc, i); + } + } + + @Benchmark + public void intMaskNot() { + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm = VectorMask.fromArray(I_SPECIES, ma, i); + vm.not().intoArray(mc, i); + } + } + + @Benchmark + public void longMaskNot() { + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm = VectorMask.fromArray(L_SPECIES, ma, i); + vm.not().intoArray(mc, i); + } + } + + @Benchmark + public void byteMaskNand() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.and(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskNand() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.and(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void intMaskNand() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.and(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void longMaskNand() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.and(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void byteMaskNor() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.or(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskNor() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.or(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void intMaskNor() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.or(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void longMaskNor() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.or(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void byteMaskXnor() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.xor(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskXnor() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.xor(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void intMaskXnor() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.xor(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void longMaskXnor() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.xor(vm2).not().intoArray(mc, i); + } + } + + @Benchmark + public void byteMaskEq() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.eq(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskEq() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.eq(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void intMaskEq() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.eq(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void longMaskEq() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.eq(vm2).intoArray(mc, i); + } + } + + @Benchmark + public void byteMaskOrNot() { + VectorMask vm1 = VectorMask.fromArray(B_SPECIES, ma, 0); + for (int i = 0; i < B_SPECIES.loopBound(size); i += B_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(B_SPECIES, mb, i); + vm1.or(vm2.not()).intoArray(mc, i); + } + } + + @Benchmark + public void shortMaskOrNot() { + VectorMask vm1 = VectorMask.fromArray(S_SPECIES, ma, 0); + for (int i = 0; i < S_SPECIES.loopBound(size); i += S_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(S_SPECIES, mb, i); + vm1.or(vm2.not()).intoArray(mc, i); + } + } + + @Benchmark + public void intMaskOrNot() { + VectorMask vm1 = VectorMask.fromArray(I_SPECIES, ma, 0); + for (int i = 0; i < I_SPECIES.loopBound(size); i += I_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(I_SPECIES, mb, i); + vm1.or(vm2.not()).intoArray(mc, i); + } + } + + @Benchmark + public void longMaskOrNot() { + VectorMask vm1 = VectorMask.fromArray(L_SPECIES, ma, 0); + for (int i = 0; i < L_SPECIES.loopBound(size); i += L_SPECIES.length()) { + VectorMask vm2 = VectorMask.fromArray(L_SPECIES, mb, i); + vm1.or(vm2.not()).intoArray(mc, i); + } + } + @Benchmark public int highMaskRegisterPressureWithNots() { int res = 0; @@ -114,4 +326,4 @@ public int highMaskRegisterPressureWithNots() { } return res; } -} \ No newline at end of file +} From 4690ea700a053fe3c9425237bafd94161f1cac4e Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 26 Aug 2026 06:04:32 +0000 Subject: [PATCH 079/223] 8379453: Fix problems with ErrorLogTimeout Reviewed-by: coleenp, sspitsyn --- src/hotspot/share/runtime/globals.hpp | 6 +-- src/hotspot/share/utilities/vmError.cpp | 37 +++++++++---------- src/hotspot/share/utilities/vmError.hpp | 3 -- test/hotspot/gtest/runtime/test_globals.cpp | 2 +- .../jtreg/serviceability/sa/ClhsdbFlags.java | 4 +- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index edfcf2e53629..5288c6584b4b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -521,10 +521,10 @@ const int ObjectAlignmentInBytes = 8; product(bool, CreateCoredumpOnCrash, true, \ "Create core/mini dump on VM fatal error") \ \ - product(uint64_t, ErrorLogTimeout, 2 * 60, \ + product(uint, ErrorLogTimeout, 2 * 60, \ "Timeout, in seconds, to limit the time spent on writing an " \ - "error log in case of a crash.") \ - range(0, (uint64_t)max_jlong/1000) \ + "error log in case of a crash. A value of 0 disables the " \ + "timeout.") \ \ product(bool, ErrorLogSecondaryErrorDetails, false, DIAGNOSTIC, \ "If enabled, show details on secondary crashes in the error log") \ diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 045fcc23d631..10c15b3c09e2 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -540,15 +540,11 @@ bool VMError::is_error_reported_in_current_thread() { return _first_error_tid.load_relaxed() == os::current_thread_id(); } -// Helper, return current timestamp for timeout handling. -jlong VMError::get_current_timestamp() { - return os::javaTimeNanos(); -} // Factor to translate the timestamp to seconds. -#define TIMESTAMP_TO_SECONDS_FACTOR (1000 * 1000 * 1000) +#define SECONDS_TO_NANOS_FACTOR (1000 * 1000 * 1000) void VMError::record_reporting_start_time() { - const jlong now = get_current_timestamp(); + const jlong now = os::javaTimeNanos(); _reporting_start_time.store_relaxed(now); } @@ -557,7 +553,7 @@ jlong VMError::get_reporting_start_time() { } void VMError::record_step_start_time() { - const jlong now = get_current_timestamp(); + const jlong now = os::javaTimeNanos(); _step_start_time.store_relaxed(now); } @@ -1786,15 +1782,13 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt // The current step had a timeout. Lets continue reporting with the next step. st->print_raw("[timeout occurred during error reporting in step \""); st->print_raw(_current_step_info); - st->print_cr("\"] after " INT64_FORMAT " s.", - (int64_t) - ((get_current_timestamp() - get_step_start_time()) / TIMESTAMP_TO_SECONDS_FACTOR)); + st->print_cr("\"] after " JLONG_FORMAT " s.", + ((os::javaTimeNanos() - get_step_start_time()) / SECONDS_TO_NANOS_FACTOR)); } else if (_reporting_did_timeout.load_relaxed()) { // We hit ErrorLogTimeout. Reporting will stop altogether. Let's wrap things // up, the process is about to be stopped by the WatcherThread. - st->print_cr("------ Timeout during error reporting after " INT64_FORMAT " s. ------", - (int64_t) - ((get_current_timestamp() - get_reporting_start_time()) / TIMESTAMP_TO_SECONDS_FACTOR)); + st->print_cr("------ Timeout during error reporting after " JLONG_FORMAT " s. ------", + ((os::javaTimeNanos() - get_reporting_start_time()) / SECONDS_TO_NANOS_FACTOR)); st->flush(); // Watcherthread is about to call os::die. Lets just wait. os::infinite_sleep(); @@ -2079,14 +2073,14 @@ bool VMError::check_timeout() { || (OnError != nullptr && OnError[0] != '\0') || Arguments::abort_hook() != nullptr); - const jlong now = get_current_timestamp(); + const jlong now = os::javaTimeNanos(); // Global timeout hit? if (!ignore_global_timeout) { const jlong reporting_start_time = get_reporting_start_time(); // Timestamp is stored in nanos. if (reporting_start_time > 0) { - const jlong end = reporting_start_time + (jlong)ErrorLogTimeout * TIMESTAMP_TO_SECONDS_FACTOR; + const jlong end = reporting_start_time + (jlong)ErrorLogTimeout * SECONDS_TO_NANOS_FACTOR; if (end <= now && !_reporting_did_timeout.load_relaxed()) { // We hit ErrorLogTimeout and we haven't interrupted the reporting // thread yet. @@ -2100,11 +2094,14 @@ bool VMError::check_timeout() { // Reporting step timeout? const jlong step_start_time = get_step_start_time(); if (step_start_time > 0) { - // A step times out after a quarter of the total timeout. Steps are mostly fast unless they - // hang for some reason, so this simple rule allows for three hanging step and still - // hopefully leaves time enough for the rest of the steps to finish. - const int max_step_timeout_secs = 5; - const jlong timeout_duration = MAX2((jlong)max_step_timeout_secs, (jlong)ErrorLogTimeout * TIMESTAMP_TO_SECONDS_FACTOR / 4); + // Steps are very fast. If they are not fast, they typically hang without recovering. There are a few + // exceptions to this (printing a callstack from debug information located on a slow file system, or + // printing a memory map of an extremely fragmented process). To give those rare slow steps enough + // breathing space while still allowing us to skip any hanging steps, we use a per-step timeout of + // /4, or 5 seconds, whichever is smaller. + const jlong step_timeout_nanos = ((jlong)ErrorLogTimeout * SECONDS_TO_NANOS_FACTOR) / 4; + const jlong max_step_timeout_nanos = 5LL * SECONDS_TO_NANOS_FACTOR; + const jlong timeout_duration = MIN2(max_step_timeout_nanos, step_timeout_nanos); const jlong end = step_start_time + timeout_duration; if (end <= now && !_step_did_timeout.load_relaxed()) { // The step timed out and we haven't interrupted the reporting diff --git a/src/hotspot/share/utilities/vmError.hpp b/src/hotspot/share/utilities/vmError.hpp index b46ba2087884..f5c78ee7f8aa 100644 --- a/src/hotspot/share/utilities/vmError.hpp +++ b/src/hotspot/share/utilities/vmError.hpp @@ -133,9 +133,6 @@ class VMError : public AllStatic { static void reporting_started(); static void interrupt_reporting_thread(); - // Helper function to get the current timestamp. - static jlong get_current_timestamp(); - // Accessors to get/set the start times for step and total timeout. static void record_reporting_start_time(); static jlong get_reporting_start_time(); diff --git a/test/hotspot/gtest/runtime/test_globals.cpp b/test/hotspot/gtest/runtime/test_globals.cpp index e88f930ff731..dab80ca3d5a3 100644 --- a/test/hotspot/gtest/runtime/test_globals.cpp +++ b/test/hotspot/gtest/runtime/test_globals.cpp @@ -58,7 +58,7 @@ TEST_VM(FlagGuard, size_t_flag) { } TEST_VM(FlagGuard, uint64_t_flag) { - TEST_FLAG(ErrorLogTimeout, uint64_t, 1337); + TEST_FLAG(MaxDirectMemorySize, uint64_t, 4294967297); } TEST_VM(FlagGuard, double_flag) { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java index 1c8cf7191dd2..36f4d9cf2fcd 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java @@ -109,7 +109,7 @@ public static void runAllTypesTest() throws Exception { "-XX:NativeMemoryTracking=off", // ccstr "-XX:OnError='echo error'", // ccstrlist "-XX:CompileThresholdScaling=1.0", // double - "-XX:ErrorLogTimeout=120"); // uint64_t + "-XX:MaxDirectMemorySize=4294967297"); // uint64_t theApp = new LingeredApp(); LingeredApp.startAppExactJvmOpts(theApp, vmArgs); System.out.println("Started LingeredApp with pid " + theApp.getPid()); @@ -127,7 +127,7 @@ public static void runAllTypesTest() throws Exception { "NativeMemoryTracking = \"off\"", "OnError = \"'echo error'\"", "CompileThresholdScaling = 1.0", - "ErrorLogTimeout = 120")); + "MaxDirectMemorySize = 4294967297")); test.run(theApp.getPid(), cmds, expStrMap, null); } catch (Exception ex) { From 58c3b265fbcd51b33b1734f0e12c85e7bdcc31e1 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 26 Aug 2026 07:22:41 +0000 Subject: [PATCH 080/223] 8390337: [Valhalla] Missing stopped() check in Parse::acmp_type_check Reviewed-by: qamai, rcastanedalo, chagedorn --- src/hotspot/share/opto/parse2.cpp | 24 +++--- .../TestACmpWithNullCheckTrap.java | 75 +++++++++++++++++++ 2 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 133744ee8bca..3d548e93eac1 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -2076,19 +2076,21 @@ void Parse::acmp_type_check(Node* input, const TypeOopPtr* tinput, ProfilePtrKin Node* null_ctl; Node* cast = acmp_null_check(input, tinput, input_ptr, null_ctl); - if (input_type != nullptr) { - Deoptimization::DeoptReason reason; - if (tinput->speculative_type() != nullptr && !too_many_traps_or_recompiles(Deoptimization::Reason_speculate_class_check)) { - reason = Deoptimization::Reason_speculate_class_check; + if (!stopped()) { + if (input_type != nullptr) { + Deoptimization::DeoptReason reason; + if (tinput->speculative_type() != nullptr && !too_many_traps_or_recompiles(Deoptimization::Reason_speculate_class_check)) { + reason = Deoptimization::Reason_speculate_class_check; + } else { + reason = Deoptimization::Reason_class_check; + } + acmp_type_check_or_trap(&cast, input_type, reason); } else { - reason = Deoptimization::Reason_class_check; + // No specific type, check for inline type + BuildCutout unless(this, inline_type_test(cast, /* is_inline = */ false), PROB_MAX); + inc_sp(2); + uncommon_trap_exact(Deoptimization::Reason_class_check, Deoptimization::Action_maybe_recompile); } - acmp_type_check_or_trap(&cast, input_type, reason); - } else { - // No specific type, check for inline type - BuildCutout unless(this, inline_type_test(cast, /* is_inline = */ false), PROB_MAX); - inc_sp(2); - uncommon_trap_exact(Deoptimization::Reason_class_check, Deoptimization::Action_maybe_recompile); } Node* ne_region = new RegionNode(2); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java new file mode 100644 index 000000000000..0fece27f90ee --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8390337 + * @summary Test C2 compilation of an inlined profiled acmp with a null operand + * @enablePreview + * @library /test/lib + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:CompileOnly=${test.main.class}::test* ${test.main.class} + */ + +import jdk.test.lib.Asserts; + +public class TestACmpWithNullCheckTrap { + static Boolean getNull() { + return null; + } + + static boolean test1(Object object) { + return object == Boolean.TRUE; + } + + static boolean test2(Object object) { + return object == Boolean.TRUE; + } + + static boolean testConstantNull1() { + return test1(getNull()); + } + + static boolean testConstantNull2() { + return test2(getNull()); + } + + public static void main(String[] args) { + Object obj1 = new Object(); + Object obj2 = "42"; + + // Profile the acmp with identity classes so the operand is known not to be a value object + for (int i = 0; i < 12_000; i++) { + Asserts.assertFalse(test1(obj1)); + Asserts.assertFalse(test1(obj2)); + Asserts.assertFalse(test2(obj1)); + } + + // Compile test with its profiled operand replaced by a constant null value + for (int i = 0; i < 12_000; i++) { + Asserts.assertFalse(testConstantNull1()); + Asserts.assertFalse(testConstantNull2()); + } + } +} + From 22933b73583ff30f60b30dd924a6c3ca908e7df5 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 26 Aug 2026 08:10:58 +0000 Subject: [PATCH 081/223] 8358889: C2 hits assert in backend due to malformed uncommon trap Reviewed-by: qamai, rcastanedalo --- src/hotspot/share/opto/callnode.cpp | 5 +- .../c2/TestSpilledUncommonTrapRequest.java | 79 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestSpilledUncommonTrapRequest.java diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index d2926f4ebb98..d32a824f2baf 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1261,12 +1261,13 @@ bool CallStaticJavaNode::is_uncommon_trap() const { int CallStaticJavaNode::uncommon_trap_request() const { return is_uncommon_trap() ? extract_uncommon_trap_request(this) : 0; } + int CallStaticJavaNode::extract_uncommon_trap_request(const Node* call) { #ifndef PRODUCT if (!(call->req() > TypeFunc::Parms && call->in(TypeFunc::Parms) != nullptr && - call->in(TypeFunc::Parms)->is_Con() && - call->in(TypeFunc::Parms)->bottom_type()->isa_int())) { + call->in(TypeFunc::Parms)->bottom_type()->isa_int() && + call->in(TypeFunc::Parms)->bottom_type()->is_int()->is_con())) { assert(in_dump() != 0, "OK if dumping"); tty->print("[bad uncommon trap]"); return 0; diff --git a/test/hotspot/jtreg/compiler/c2/TestSpilledUncommonTrapRequest.java b/test/hotspot/jtreg/compiler/c2/TestSpilledUncommonTrapRequest.java new file mode 100644 index 000000000000..74ba57086668 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSpilledUncommonTrapRequest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8358889 + * @summary Test that a spilled uncommon trap request is handled properly. + * @requires vm.compiler2.enabled + * @library /test/lib + * @run main ${test.main.class} + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -Xcomp + * -XX:StressSeed=403 -XX:+StressGCM + * -XX:CompileCommand=compileonly,${test.main.class}::test + * -XX:CompileCommand=dontinline,${test.main.class}::dontInline + * ${test.main.class} + */ + +import jdk.test.lib.Asserts; + +public class TestSpilledUncommonTrapRequest { + static long sum; + static final int[] array = new int[64]; + + static int max(int first, int second) { + return first > second ? first : second; + } + + static int dontInline() { + return 42; + } + + static void test(double[][] doubles) { + // Vectorize a loop such that Compile::current()->max_vector_size() > 0 holds + for (int i = 0; i < 64; i++) { + array[i] = i; + } + + // C2 adds an uncommon trap with 'Reason_null_check == 1' and 'Action_maybe_recompile == 1' for the + // null-check of the inner array doubles[0] here. This is encoded as + // ~((reason << 3) + action) = ~((1 << 3) + 1) = ~9 = -10 + // which is then shared with the explicit constant -10 passed as argument here. + doubles[0][0] = max(dontInline(), -10); + + // Keep the shared -10 live in a loop phi and create enough register pressure for RA to spill it. + int product = -10; + for (int i = 0; i < 64; i++) { + product *= 79; + sum++; + array[i] = 0; + } + sum += product; + } + + public static void main(String[] args) { + test(new double[1][1]); + Asserts.assertEQ(sum, 1573390390L); + } +} + From f86752b7c87d0f52e256227a8a1cee92f6b8eb81 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 26 Aug 2026 08:51:49 +0000 Subject: [PATCH 082/223] 8389938: Follow up after removing UseObjectMonitorTable flag Reviewed-by: coleenp, aboldtch, pchilanomate, shade --- .../share/gc/g1/g1ParScanThreadState.cpp | 3 +- .../gc/parallel/psPromotionManager.inline.hpp | 5 +- .../shenandoah/shenandoahGenerationalHeap.cpp | 7 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 18 +--- src/hotspot/share/oops/markWord.cpp | 86 +++++++------------ src/hotspot/share/oops/markWord.hpp | 26 +----- src/hotspot/share/oops/oop.hpp | 5 -- src/hotspot/share/oops/oop.inline.hpp | 25 +----- src/hotspot/share/prims/jvmtiEnvBase.cpp | 2 +- src/hotspot/share/runtime/basicLock.hpp | 2 + src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/objectMonitor.hpp | 17 ---- .../share/runtime/objectMonitor.inline.hpp | 12 --- src/hotspot/share/runtime/synchronizer.cpp | 16 ++-- src/hotspot/share/runtime/synchronizer.hpp | 1 - src/hotspot/share/runtime/vframe.cpp | 2 +- src/hotspot/share/services/threadService.cpp | 2 +- test/hotspot/gtest/oops/test_markWord.cpp | 9 +- ...eTest.java => ObjectMonitorTableTest.java} | 12 +-- .../gc/gp/misc/HashedGarbageProducer.java | 10 +-- 20 files changed, 64 insertions(+), 198 deletions(-) rename test/hotspot/jtreg/runtime/Monitor/{UseObjectMonitorTableTest.java => ObjectMonitorTableTest.java} (95%) diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 3a7ff7adc4f1..f120ac320357 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -351,8 +351,7 @@ G1HeapRegionAttr G1ParScanThreadState::next_region_attr(G1HeapRegionAttr const r assert(region_attr.is_young() || region_attr.is_old(), "must be either Young or Old"); if (region_attr.is_young()) { - age = !m.has_displaced_mark_helper() ? m.age() - : m.displaced_mark_helper().age(); + age = m.age(); if (age < _tenuring_threshold) { return region_attr; } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 1d8e358c72b7..2f7fb7cd970e 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,8 +249,7 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, size_t new_obj_size = o->size_given_klass(klass); // Find the objects age, MT safe. - uint age = (test_mark.has_displaced_mark_helper() /* o->has_displaced_mark() */) ? - test_mark.displaced_mark_helper().age() : test_mark.age(); + uint age = test_mark.age(); if (!promote_immediately) { // Try allocating obj in to-space (unless too old) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index ef4ee13a7d41..63a8666f816f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,10 +211,7 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) { return ShenandoahForwarding::get_forwardee(p); } - if (mark.has_displaced_mark_helper()) { - // We don't want to deal with MT here just to ensure we read the right mark word. - // Skip the potential promotion attempt for this one. - } else if (age_census()->is_tenurable(from_region->age() + mark.age())) { + if (age_census()->is_tenurable(from_region->age() + mark.age())) { // If the object is tenurable, try to promote it oop result = try_evacuate_object(p, thread, from_region->age()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index ff0271db8fda..5642d73e7262 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -301,32 +301,18 @@ inline HeapWord* ShenandoahHeap::allocate_from_gclab(Thread* thread, size_t size void ShenandoahHeap::increase_object_age(oop obj, uint additional_age) { // This operates on new copy of an object. This means that the object's mark-word - // is thread-local and therefore safe to access. However, when the mark is - // displaced (i.e. stack-locked or monitor-locked), then it must be considered - // a shared memory location. It can be accessed by other threads. - // In particular, a competing evacuating thread can succeed to install its copy - // as the forwardee and continue to unlock the object, at which point 'our' - // write to the foreign stack-location would potentially over-write random - // information on that stack. Writing to a monitor is less problematic, - // but still not safe: while the ObjectMonitor would not randomly disappear, - // the other thread would also write to the same displaced header location, - // possibly leading to increase the age twice. - // For all these reasons, we take the conservative approach and not attempt - // to increase the age when the header is displaced. + // is thread-local and therefore safe to access. markWord w = obj->mark(); // It is possible that we have copied the object after another thread has // already successfully completed evacuation. While harmless (we would never // publish our copy), don't even attempt to modify the age when that // happens. - if (!w.has_displaced_mark_helper() && !w.is_marked()) { + if (!w.is_marked()) { w = w.set_age(MIN2(markWord::max_age, w.age() + additional_age)); obj->set_mark(w); } } -// Return the object's age, or a sentinel value when the age can't -// necessarily be determined because of concurrent locking by the -// mutator uint ShenandoahHeap::get_object_age(oop obj) { markWord w = obj->mark(); assert(!w.is_marked(), "must not be forwarded"); diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 2201633b160a..e1220583c429 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -23,9 +23,6 @@ */ #include "oops/markWord.hpp" -#include "runtime/basicLock.inline.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/objectMonitor.inline.hpp" #include "utilities/ostream.hpp" #ifdef _LP64 @@ -34,60 +31,39 @@ STATIC_ASSERT(markWord::klass_shift + markWord::klass_bits == 64); STATIC_ASSERT(markWord::klass_shift == markWord::hash_bits + markWord::hash_shift); #endif -markWord markWord::displaced_mark_helper() const { - assert(has_displaced_mark_helper(), "check"); - // Make sure we have an inflated monitor. - guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); - ObjectMonitor* monitor = this->monitor(); - return monitor->header(); -} - -void markWord::set_displaced_mark_helper(markWord m) const { - assert(has_displaced_mark_helper(), "check"); - // Make sure we have an inflated monitor. - guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); - ObjectMonitor* monitor = this->monitor(); - monitor->set_header(m); -} - -void markWord::print_on(outputStream* st, bool print_monitor_info) const { - if (is_marked()) { // last bits = 11 +void markWord::print_on(outputStream* st) const { + if (is_marked()) { // last bits = 11 st->print(" marked(" INTPTR_FORMAT ")", value()); - } else if (has_monitor()) { // last bits = 10 - // have to check has_monitor() before is_locked() - // Valhalla: inline types/arrays can't be monitored - st->print(" monitor(" INTPTR_FORMAT ")=", value()); - } else if (is_locked()) { // last bits != 01 => 00 - // thin locked - // Valhalla: inline types can not possess an object monitor - st->print(" locked(" INTPTR_FORMAT ")", value()); + return; + } + st->print(" mark("); + if (has_monitor()) { // last bits = 10 + st->print("has_monitor"); + } else if (is_unlocked()) { // last bits = 01 + st->print("is_unlocked"); + } else { // last bits = 00 + assert(is_fast_locked(), "should be"); + st->print("is_locked"); + } + if (is_inline_type()) { + st->print(" inline_type"); + } + if (has_no_hash()) { + st->print(" no_hash"); } else { - st->print(" mark("); - if (is_unlocked()) { // last bits = 01 - st->print("is_unlocked"); - if (is_inline_type()) { - st->print(" inline_type"); - } - if (has_no_hash()) { - st->print(" no_hash"); - } else { - st->print(" hash=" INTPTR_FORMAT, hash()); - } + st->print(" hash=" INTPTR_FORMAT, hash()); + } #ifdef _LP64 // 64 bit encodings have array information - // flat or null-free do not imply each other - bool flat = is_flat_array(); - bool null_free = is_null_free_array(); - if (flat && !null_free) { - st->print(" flat_array"); - } else if (!flat && null_free) { - st->print(" null_free_array"); - } else if (flat && null_free) { - st->print(" flat_null_free_array"); - } -#endif - } else { - st->print("??"); - } - st->print(" age=%d)", age()); + // flat or null-free do not imply each other + const bool flat = is_flat_array(); + const bool null_free = is_null_free_array(); + if (flat && !null_free) { + st->print(" flat_array"); + } else if (!flat && null_free) { + st->print(" null_free_array"); + } else if (flat && null_free) { + st->print(" flat_null_free_array"); } +#endif + st->print(" age=%d)", age()); } diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 42ced7df0b2d..63bcd27c3397 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -82,7 +82,6 @@ // // - klass - klass identifier used when UseCompactObjectHeaders == true -class ObjectMonitor; class outputStream; class markWord { @@ -253,27 +252,6 @@ class markWord { markWord set_has_monitor() const { return markWord((value() & ~lock_mask_in_place) | monitor_value); } - ObjectMonitor* monitor() const { - // Locking with OM table does not use markWord for monitors. - ShouldNotCallThis(); - return (ObjectMonitor*) nullptr; - } - - static markWord encode(ObjectMonitor* monitor) { - // Locking with OM table does not use markWord for monitors. - ShouldNotCallThis(); - return markWord(0); - } - - bool has_monitor_pointer() const { - return false; // Locking with OM table does not use markWord for monitors. - } - - bool has_displaced_mark_helper() const { - return has_monitor_pointer(); - } - markWord displaced_mark_helper() const; - void set_displaced_mark_helper(markWord m) const; // used to encode pointers during GC markWord clear_lock_bits() const { return markWord(value() & ~lock_mask_in_place); } @@ -299,7 +277,6 @@ class markWord { } bool is_flat_array() const { - assert(!has_monitor_pointer(), "Bits are not valid if replaced by a monitor pointer: " PTR_FORMAT, value()); assert(!is_marked(), "Bits might not be valid if marked by the GC: " PTR_FORMAT, value()); #ifdef _LP64 // 64 bit encodings only return (mask_bits(value(), flat_array_bit_in_place) != 0); @@ -309,7 +286,6 @@ class markWord { } bool is_null_free_array() const { - assert(!has_monitor_pointer(), "Bits are not valid if replaced by a monitor pointer: " PTR_FORMAT, value()); assert(!is_marked(), "Bits might not be valid if marked by the GC: " PTR_FORMAT, value()); #ifdef _LP64 // 64 bit encodings only return (mask_bits(value(), null_free_array_bit_in_place) != 0); @@ -356,7 +332,7 @@ class markWord { } // Debugging - void print_on(outputStream* st, bool print_monitor_info = true) const; + void print_on(outputStream* st) const; // Prepare address of oop for placement into mark inline static markWord encode_pointer_as_mark(void* p) { return from_pointer(p).set_marked(); } diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 831250b81a47..0b2e2aa49d20 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -320,11 +320,6 @@ class oopDesc { intptr_t slow_identity_hash(); inline bool fast_no_hash_check(); - // marks are forwarded to stack when object is locked - inline bool has_displaced_mark() const; - inline markWord displaced_mark() const; - inline void set_displaced_mark(markWord m); - // Checks if the mark word needs to be preserved inline bool mark_must_be_preserved() const; inline bool mark_must_be_preserved(markWord m) const; diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index fb536b923c40..fb4309049cb3 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -339,7 +339,6 @@ oop oopDesc::forwardee(markWord mark) const { } } -// Note that the forwardee is not the same thing as the displaced_mark. // The forwardee is used when copying during scavenge and mark-sweep. // It does need to clear the low two locking- and GC-related bits. oop oopDesc::forwardee() const { @@ -354,21 +353,13 @@ void oopDesc::unset_self_forwarded() { uint oopDesc::age() const { markWord m = mark(); assert(!m.is_marked(), "Attempt to read age from forwarded mark"); - if (m.has_displaced_mark_helper()) { - return m.displaced_mark_helper().age(); - } else { - return m.age(); - } + return m.age(); } void oopDesc::incr_age() { markWord m = mark(); assert(!m.is_marked(), "Attempt to increment age of forwarded mark"); - if (m.has_displaced_mark_helper()) { - m.set_displaced_mark_helper(m.displaced_mark_helper().incr_age()); - } else { - set_mark(m.incr_age()); - } + set_mark(m.incr_age()); } template @@ -434,18 +425,6 @@ bool oopDesc::fast_no_hash_check() { return mrk.is_unlocked() && mrk.has_no_hash(); } -bool oopDesc::has_displaced_mark() const { - return mark().has_displaced_mark_helper(); -} - -markWord oopDesc::displaced_mark() const { - return mark().displaced_mark_helper(); -} - -void oopDesc::set_displaced_mark(markWord m) { - mark().set_displaced_mark_helper(m); -} - bool oopDesc::mark_must_be_preserved() const { return mark_must_be_preserved(mark()); } diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 389ac7f43688..13325523684b 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1545,7 +1545,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec GrowableArray* wantList = nullptr; ObjectMonitor* mon = mark.has_monitor() - ? ObjectSynchronizer::read_monitor(hobj(), mark) + ? ObjectSynchronizer::read_monitor(hobj()) : nullptr; if (mon != nullptr) { diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index 26d1c2e762a8..ed580510aaf2 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -31,6 +31,8 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/sizes.hpp" +class ObjectMonitor; + class BasicLock { friend class VMStructs; private: diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index a0d304fe1584..ce271e35cdd4 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1503,7 +1503,7 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArrayowner()->is_locked(), "object must be locked now"); assert(obj->mark().has_monitor(), "must be"); assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); - assert(ObjectSynchronizer::read_monitor(obj(), obj->mark())->has_owner(deoptee_thread), "must be"); + assert(ObjectSynchronizer::read_monitor(obj())->has_owner(deoptee_thread), "must be"); } } } diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 3c126a034484..52bbebec88d5 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -217,27 +217,10 @@ class ObjectMonitor : public CHeapObj { static ByteSize succ_offset() { return byte_offset_of(ObjectMonitor, _succ); } static ByteSize entry_list_offset() { return byte_offset_of(ObjectMonitor, _entry_list); } - // ObjectMonitor references can be ORed with markWord::monitor_value - // as part of the ObjectMonitor tagging mechanism. When we combine an - // ObjectMonitor reference with an offset, we need to remove the tag - // value in order to generate the proper address. - // - // We can either adjust the ObjectMonitor reference and then add the - // offset or we can adjust the offset that is added to the ObjectMonitor - // reference. The latter avoids an AGI (Address Generation Interlock) - // stall so the helper macro adjusts the offset value that is returned - // to the ObjectMonitor reference manipulation code: - // - #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \ - ((in_bytes(ObjectMonitor::f ## _offset())) - checked_cast(markWord::monitor_value)) - uintptr_t metadata() const; void set_metadata(uintptr_t value); volatile uintptr_t* metadata_addr(); - markWord header() const; - void set_header(markWord hdr); - intptr_t hash() const; void set_hash(intptr_t hash); diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 5e9d3dee5624..238c035c4b46 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -74,18 +74,6 @@ inline volatile uintptr_t* ObjectMonitor::metadata_addr() { return &_metadata; } -inline markWord ObjectMonitor::header() const { - // Locking with OM table does not use header. - ShouldNotCallThis(); - return markWord(metadata()); -} - -inline void ObjectMonitor::set_header(markWord hdr) { - // Locking with OM table does not use header. - ShouldNotCallThis(); - set_metadata(hdr.value()); -} - inline intptr_t ObjectMonitor::hash() const { return metadata(); } diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index fb2f8bd43033..d05f1d3e9c26 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -373,7 +373,7 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al } if (mark.has_monitor()) { - ObjectMonitor* const mon = read_monitor(obj, mark); + ObjectMonitor* const mon = read_monitor(obj); if (mon == nullptr) { // Racing with inflation/deflation go slow path return false; @@ -715,7 +715,7 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, } while (mark.has_monitor()) { - ObjectMonitor* monitor = read_monitor(obj, mark); + ObjectMonitor* monitor = read_monitor(obj); if (monitor != nullptr) { return monitor->is_entered(current) != 0; } @@ -744,7 +744,7 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob } while (mark.has_monitor()) { - ObjectMonitor* monitor = read_monitor(obj, mark); + ObjectMonitor* monitor = read_monitor(obj); if (monitor != nullptr) { return Threads::owning_thread_from_monitor(t_list, monitor); } @@ -1377,7 +1377,7 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, } const markWord mark = obj->mark(); - ObjectMonitor* const obj_mon = read_monitor(obj, mark); + ObjectMonitor* const obj_mon = read_monitor(obj); if (n != obj_mon) { out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " "object does not refer to the same monitor: obj=" @@ -1660,7 +1660,7 @@ bool ObjectSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stack, Ja return true; } else if (observed_deflation) { // Spin while monitor is being deflated. - ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(obj, mark); + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(obj); return monitor == nullptr || monitor->is_being_async_deflated(); } // Else stop spinning. @@ -1860,7 +1860,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchro } assert(mark.has_monitor(), "must be"); - ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(obj, mark); + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(obj); if (monitor != nullptr) { if (monitor->has_anonymous_owner()) { LockStack& lock_stack = current->lock_stack(); @@ -2090,10 +2090,6 @@ ObjectMonitor* ObjectSynchronizer::get_monitor_from_table(oop obj) { } ObjectMonitor* ObjectSynchronizer::read_monitor(oop obj) { - return ObjectSynchronizer::read_monitor(obj, obj->mark()); -} - -ObjectMonitor* ObjectSynchronizer::read_monitor(oop obj, markWord mark) { return ObjectSynchronizer::get_monitor_from_table(obj); } diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 922d988e290a..66588e82bcd2 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -126,7 +126,6 @@ class ObjectSynchronizer : AllStatic { static const char* inflate_cause_name(const InflateCause cause); static ObjectMonitor* read_monitor(oop obj); - static ObjectMonitor* read_monitor(oop obj, markWord mark); // Returns the identity hash value for an oop // NOTE: It may cause monitor inflation diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index b5243fd03b32..e0a3ffbcf510 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -248,7 +248,7 @@ void javaVFrame::print_lock_info_on(outputStream* st, bool is_virtual, int frame // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. if (mark.has_monitor()) { - ObjectMonitor* mon = ObjectSynchronizer::read_monitor(monitor->owner(), mark); + ObjectMonitor* mon = ObjectSynchronizer::read_monitor(monitor->owner()); if (// if the monitor is null we must be in the process of locking mon == nullptr || // we have marked ourself as pending on this monitor diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 6e18732284b3..37a672556a29 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1258,7 +1258,7 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. if (mark.has_monitor()) { - ObjectMonitor* mon = ObjectSynchronizer::read_monitor(monitor->owner(), mark); + ObjectMonitor* mon = ObjectSynchronizer::read_monitor(monitor->owner()); if (// if the monitor is null we must be in the process of locking mon == nullptr || // we have marked ourself as pending on this monitor diff --git a/test/hotspot/gtest/oops/test_markWord.cpp b/test/hotspot/gtest/oops/test_markWord.cpp index 35a8c7bb66f7..29f16f0753fd 100644 --- a/test/hotspot/gtest/oops/test_markWord.cpp +++ b/test/hotspot/gtest/oops/test_markWord.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ class LockerThread : public JavaTestThread { // state we have... ObjectLocker ol(h_obj, THREAD); ol.notify_all(THREAD); - assert_test_pattern(h_obj, "monitor"); + assert_test_pattern(h_obj, "has_monitor"); } }; @@ -91,7 +91,7 @@ TEST_VM(markWord, printing) { // Thread tries to lock it. { ObjectLocker ol(h_obj, THREAD); - assert_mark_word_print_pattern(h_obj, "locked"); + assert_mark_word_print_pattern(h_obj, "is_locked"); } assert_mark_word_print_pattern(h_obj, "is_unlocked no_hash"); @@ -109,13 +109,12 @@ TEST_VM(markWord, printing) { st->doit(); ol.wait_uninterruptibly(THREAD); - assert_test_pattern(h_obj, "monitor"); + assert_test_pattern(h_obj, "has_monitor"); done.wait_with_safepoint_check(THREAD); // wait till the thread is done. } } static void assert_unlocked_state(markWord mark) { - EXPECT_FALSE(mark.has_displaced_mark_helper()); EXPECT_FALSE(mark.is_fast_locked()); EXPECT_FALSE(mark.has_monitor()); EXPECT_FALSE(mark.is_locked()); diff --git a/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java b/test/hotspot/jtreg/runtime/Monitor/ObjectMonitorTableTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java rename to test/hotspot/jtreg/runtime/Monitor/ObjectMonitorTableTest.java index fd6ece349a24..45d1f2370329 100644 --- a/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java +++ b/test/hotspot/jtreg/runtime/Monitor/ObjectMonitorTableTest.java @@ -24,9 +24,9 @@ /** * @test id=NormalDeflation * @summary A collection of small tests using synchronized, wait, notify to try - * and achieve good cheap coverage of UseObjectMonitorTable. + * and achieve good cheap coverage of ObjectMonitorTable. * @library /test/lib - * @run main/othervm UseObjectMonitorTableTest + * @run main/othervm ObjectMonitorTableTest */ /** @@ -35,7 +35,7 @@ * @library /test/lib * @run main/othervm -XX:+UnlockDiagnosticVMOptions * -XX:GuaranteedAsyncDeflationInterval=1 - * UseObjectMonitorTableTest + * ObjectMonitorTableTest */ import jdk.test.lib.Utils; @@ -48,7 +48,7 @@ import java.util.Random; import java.util.stream.Stream; -public class UseObjectMonitorTableTest { +public class ObjectMonitorTableTest { static final ThreadFactory TF = Executors.defaultThreadFactory(); static class WaitNotifyTest implements Runnable { @@ -232,10 +232,10 @@ public static void main(String[] args) { try { t.join(); } catch (InterruptedException e) { - throw new RuntimeException("UseObjectMonitorTableTest: Unexpected interrupt", e); + throw new RuntimeException("ObjectMonitorTableTest: Unexpected interrupt", e); } }); - System.out.println("UseObjectMonitorTableTest passed."); + System.out.println("ObjectMonitorTableTest passed."); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java index db24db8b9a75..b3190f404732 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,14 +31,6 @@ */ /* - The description is misleading. I looked at some old email, and the - goal is to stress the code that deals with displaced mark words, so - the description should be more like "Stress tests for displaced mark - words." In hotspot, each object has a mark word that stores several - things about the object including its hash code (if it has one) and - lock state. Most objects never have a hash code and are never locked, - so the mark word is empty. - Most of our garbage collectors use the mark word temporarily during GC to store a 'forwarding pointer.' It's not important what that is, but it means that objects that have a hash code or that are locked have to From c436633bb9be5854bc8c7eacdde3faae28aef3a9 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Wed, 26 Aug 2026 09:06:21 +0000 Subject: [PATCH 083/223] 8391044: [zgc] unused parameter "node" in z_color and z_uncolor Reviewed-by: eosterlund, fyang --- src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad | 28 +++++++++++------------ src/hotspot/cpu/riscv/gc/z/z_riscv.ad | 26 ++++++++++----------- src/hotspot/cpu/x86/gc/z/z_x86_64.ad | 18 +++++++-------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 74e0395c81ec..11b70e4e8384 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -33,14 +33,14 @@ source %{ #include "gc/z/zBarrierSetAssembler.hpp" -static void z_color(MacroAssembler* masm, const MachNode* node, Register dst, Register src) { +static void z_color(MacroAssembler* masm, Register dst, Register src) { assert_different_registers(src, dst); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodBeforeMov); __ movzw(dst, barrier_Relocation::unpatched); __ orr(dst, dst, src, Assembler::LSL, ZPointerLoadShift); } -static void z_uncolor(MacroAssembler* masm, const MachNode* node, Register ref) { +static void z_uncolor(MacroAssembler* masm, Register ref) { __ lsr(ref, ref, ZPointerLoadShift); } @@ -50,7 +50,7 @@ static void z_keep_alive_load_barrier(MacroAssembler* masm, const MachNode* node __ tst(ref, tmp); ZLoadBarrierStubC2Aarch64* const stub = ZLoadBarrierStubC2Aarch64::create(node, ref_addr, ref); __ br(Assembler::NE, *stub->entry()); - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); __ bind(*stub->continuation()); } @@ -66,7 +66,7 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r } if (node->barrier_data() == ZBarrierElided) { - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); return; } @@ -81,14 +81,14 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r __ b(*stub->entry()); __ bind(good); } - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); __ bind(*stub->continuation()); } static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register rnew_zaddress, Register rnew_zpointer, Register tmp, bool is_atomic) { Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); if (node->barrier_data() == ZBarrierElided) { - z_color(masm, node, rnew_zpointer, rnew_zaddress); + z_color(masm, rnew_zpointer, rnew_zaddress); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; @@ -206,7 +206,7 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, rscratch2, true /* is_atomic */); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::xword, memory_order_release); __ cset($res$$Register, Assembler::EQ); %} @@ -229,7 +229,7 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, rscratch2, true /* is_atomic */); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::xword, memory_order_seq_cst); __ cset($res$$Register, Assembler::EQ); %} @@ -251,10 +251,10 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, rscratch2, true /* is_atomic */); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::xword, memory_order_release, $res$$Register); - z_uncolor(masm, this, $res$$Register); + z_uncolor(masm, $res$$Register); %} ins_pipe(pipe_slow); @@ -274,10 +274,10 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, rscratch2, true /* is_atomic */); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::xword, memory_order_seq_cst, $res$$Register); - z_uncolor(masm, this, $res$$Register); + z_uncolor(masm, $res$$Register); %} ins_pipe(pipe_slow); @@ -295,7 +295,7 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ ins_encode %{ z_store_barrier(masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, rscratch2, true /* is_atomic */); __ atomic_xchg($prev$$Register, $prev$$Register, $mem$$Register); - z_uncolor(masm, this, $prev$$Register); + z_uncolor(masm, $prev$$Register); %} ins_pipe(pipe_serial); @@ -313,7 +313,7 @@ instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) ins_encode %{ z_store_barrier(masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, rscratch2, true /* is_atomic */); __ atomic_xchgal($prev$$Register, $prev$$Register, $mem$$Register); - z_uncolor(masm, this, $prev$$Register); + z_uncolor(masm, $prev$$Register); %} ins_pipe(pipe_serial); diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad index 0078deb76e8c..a922f5337b2c 100644 --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad @@ -33,7 +33,7 @@ source_hpp %{ source %{ #include "gc/z/zBarrierSetAssembler.hpp" -static void z_color(MacroAssembler* masm, const MachNode* node, Register dst, Register src, Register tmp) { +static void z_color(MacroAssembler* masm, Register dst, Register src, Register tmp) { assert_different_registers(dst, tmp); __ relocate(barrier_Relocation::spec(), [&] { @@ -43,7 +43,7 @@ static void z_color(MacroAssembler* masm, const MachNode* node, Register dst, Re __ orr(dst, dst, tmp); } -static void z_uncolor(MacroAssembler* masm, const MachNode* node, Register ref) { +static void z_uncolor(MacroAssembler* masm, Register ref) { __ srli(ref, ref, ZPointerLoadShift); } @@ -63,7 +63,7 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r ((node->barrier_data() & ZBarrierPhantom) != 0); if (node->barrier_data() == ZBarrierElided) { - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); return; } @@ -74,14 +74,14 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r __ j(*stub->entry()); __ bind(good); - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); __ bind(*stub->continuation()); } static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register rnew_zaddress, Register rnew_zpointer, Register tmp, bool is_atomic) { Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); if (node->barrier_data() == ZBarrierElided) { - z_color(masm, node, rnew_zpointer, rnew_zaddress, tmp); + z_color(masm, rnew_zpointer, rnew_zaddress, tmp); } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0; @@ -145,7 +145,7 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva ins_encode %{ guarantee($mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, true /* result_as_bool */); %} @@ -168,7 +168,7 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne ins_encode %{ guarantee($mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, true /* result_as_bool */); %} @@ -189,10 +189,10 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n ins_encode %{ guarantee($mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register); - z_uncolor(masm, this, $res$$Register); + z_uncolor(masm, $res$$Register); %} ins_pipe(pipe_slow); @@ -211,10 +211,10 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg ins_encode %{ guarantee($mem$$disp == 0, "impossible encoding"); Address ref_addr($mem$$Register); - z_color(masm, this, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); + z_color(masm, $oldval_tmp$$Register, $oldval$$Register, $tmp1$$Register); z_store_barrier(masm, this, ref_addr, $newval$$Register, $newval_tmp$$Register, $tmp1$$Register, true /* is_atomic */); __ cmpxchg($mem$$Register, $oldval_tmp$$Register, $newval_tmp$$Register, Assembler::int64, Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register); - z_uncolor(masm, this, $res$$Register); + z_uncolor(masm, $res$$Register); %} ins_pipe(pipe_slow); @@ -232,7 +232,7 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rF ins_encode %{ z_store_barrier(masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, $tmp$$Register, true /* is_atomic */); __ atomic_xchg($prev$$Register, $prev$$Register, $mem$$Register); - z_uncolor(masm, this, $prev$$Register); + z_uncolor(masm, $prev$$Register); %} ins_pipe(pipe_serial); @@ -250,7 +250,7 @@ instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, ins_encode %{ z_store_barrier(masm, this, Address($mem$$Register), $newv$$Register, $prev$$Register, $tmp$$Register, true /* is_atomic */); __ atomic_xchgal($prev$$Register, $prev$$Register, $mem$$Register); - z_uncolor(masm, this, $prev$$Register); + z_uncolor(masm, $prev$$Register); %} ins_pipe(pipe_serial); %} diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index 0c640dde285c..af74e29fb6fe 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -34,14 +34,14 @@ source %{ #include "c2_intelJccErratum_x86.hpp" #include "gc/z/zBarrierSetAssembler.hpp" -static void z_color(MacroAssembler* masm, const MachNode* node, Register ref) { +static void z_color(MacroAssembler* masm, Register ref) { __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(ref, barrier_Relocation::unpatched); __ orq_imm32(ref, barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } -static void z_uncolor(MacroAssembler* masm, const MachNode* node, Register ref) { +static void z_uncolor(MacroAssembler* masm, Register ref) { __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shrq(ref, barrier_Relocation::unpatched); } @@ -53,7 +53,7 @@ static void z_keep_alive_load_barrier(MacroAssembler* masm, const MachNode* node ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref); __ jcc(Assembler::notEqual, *stub->entry()); - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); __ bind(*stub->continuation()); } @@ -69,7 +69,7 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r return; } - z_uncolor(masm, node, ref); + z_uncolor(masm, ref); if (node->barrier_data() == ZBarrierElided) { return; } @@ -87,7 +87,7 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address if (rnew_zaddress != noreg) { // noreg means null; no need to color __ movptr(rnew_zpointer, rnew_zaddress); - z_color(masm, node, rnew_zpointer); + z_color(masm, rnew_zpointer); } } else { bool is_native = (node->barrier_data() & ZBarrierNative) != 0; @@ -200,10 +200,10 @@ instruct zCompareAndExchangeP(indirect mem, no_rax_RegP newval, rRegP tmp, rax_R assert_different_registers($oldval$$Register, $newval$$Register); const Address mem_addr = Address($mem$$Register, 0); z_store_barrier(masm, this, mem_addr, $newval$$Register, $tmp$$Register, true /* is_atomic */); - z_color(masm, this, $oldval$$Register); + z_color(masm, $oldval$$Register); __ lock(); __ cmpxchgptr($tmp$$Register, mem_addr); - z_uncolor(masm, this, $oldval$$Register); + z_uncolor(masm, $oldval$$Register); %} ins_pipe(pipe_cmpxchg); @@ -223,7 +223,7 @@ instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rax_ assert_different_registers($oldval$$Register, $mem$$Register); const Address mem_addr = Address($mem$$Register, 0); z_store_barrier(masm, this, mem_addr, $newval$$Register, $tmp$$Register, true /* is_atomic */); - z_color(masm, this, $oldval$$Register); + z_color(masm, $oldval$$Register); __ lock(); __ cmpxchgptr($tmp$$Register, mem_addr); __ setcc(Assembler::equal, $res$$Register); @@ -245,7 +245,7 @@ instruct zXChgP(indirect mem, rRegP newval, rRegP tmp, rFlagsReg cr) %{ z_store_barrier(masm, this, mem_addr, $newval$$Register, $tmp$$Register, true /* is_atomic */); __ movptr($newval$$Register, $tmp$$Register); __ xchgptr($newval$$Register, mem_addr); - z_uncolor(masm, this, $newval$$Register); + z_uncolor(masm, $newval$$Register); %} ins_pipe(pipe_cmpxchg); From 3e4637bdc8ba1c0e93abd4d9a4fdc309fce97a66 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 26 Aug 2026 09:59:59 +0000 Subject: [PATCH 084/223] 8387571: Typos/grammar/duplicated word/missing hyperlink errors in javac man page Reviewed-by: vromero --- src/jdk.compiler/share/man/javac.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index c749ca4da10c..47d0d7f04eee 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -139,7 +139,7 @@ file system locations may be directories, JAR files or JMOD files. `@`*filename* : Reads options and file names from a file. To shorten or simplify the `javac` command, you can specify one or more files that contain arguments - to the `javac` command (except [`-J`](#option-J) options). This lets you to create + to the `javac` command (except [`-J`](#option-J) options). This lets you create `javac` commands of any length on any operating system. See [Command-Line Argument Files]. @@ -233,7 +233,7 @@ file system locations may be directories, JAR files or JMOD files. If you are compiling for a release of the platform that supports the Extension Mechanism, then this option specifies the directories that contain the extension classes. - See [Compiling for Other Releases of the Platform]. + See [Compiling for Earlier Releases of the Platform]. **Note:** This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in [`--release`](#option-release), [`-source`](#option-source), or @@ -297,7 +297,7 @@ file system locations may be directories, JAR files or JMOD files. `-J`*option* : Passes *option* to the runtime system, where *option* is one of the Java - options described on [java](java.html) command. For example, `-J-Xms48m` + options described for the [java](java.html) command. For example, `-J-Xms48m` sets the startup memory to 48 MB. **Note:** The `CLASSPATH` environment variable, `-classpath` option, `-bootclasspath` @@ -1150,7 +1150,7 @@ This may be useful when performing white-box testing; relying on access to internal API in production code is strongly discouraged. You can patch additional content into any module using the -[`--patch-module`](#option-patch-module) option. See [Patching a Module] for more details. +[`--patch-module`](#option-patch-module) option. See [Patching Modules] for more details. ## Searching for Module, Package and Type Declarations @@ -1234,7 +1234,7 @@ If the module is one of those currently being compiled, the module declaration will be either the file named `module-info.class` in the root of the package hierarchy for the module in the class output directory, or the file named `module-info.java` in one of the locations on the source path -or one the module source path for the module. +or on the module source path for the module. ### Searching for the Declaration of a Type When the Reference is not in a Module @@ -1273,7 +1273,7 @@ readable by the enclosing module. If so, `javac` will simply and directly go to the definition of that module to find the definition of the required type. Unless the module is another of the modules being compiled, `javac` will -only look for compiled class files files. In other words, `javac` will +only look for compiled class files. In other words, `javac` will not look for source files in platform modules or modules on the module path. If the type being referenced is not in some other readable module, @@ -1476,7 +1476,7 @@ specified, then the user class path is used. Processors are located by means of service provider-configuration files named `META-INF/services/javax.annotation.processing.Processor` on the search path. Such files should contain the names of any -annotationation processors to be used, listed one per +annotation processors to be used, listed one per line. Alternatively, processors can be specified explicitly, using the [`-processor`](#option-processor) option. @@ -1651,7 +1651,7 @@ internal and subject to change at any time. > `int divideByZero = 42 / 0;` `empty` -: Warns about empty statements after `if`statements, for example: +: Warns about empty statements after `if` statements, for example: ``` class E { From 8ca671b95ffd6df058284693750372c916bb8285 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 26 Aug 2026 10:10:51 +0000 Subject: [PATCH 085/223] 8391060: ZGC: ZMarkingSMR re-orded hazard pointer loads with unlinking results in use after free Reviewed-by: eosterlund, stefank --- src/hotspot/share/gc/z/zMarkingSMR.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/gc/z/zMarkingSMR.cpp b/src/hotspot/share/gc/z/zMarkingSMR.cpp index 0f45f1746677..35e9af34a7b9 100644 --- a/src/hotspot/share/gc/z/zMarkingSMR.cpp +++ b/src/hotspot/share/gc/z/zMarkingSMR.cpp @@ -66,6 +66,9 @@ void ZMarkingSMR::free_node(ZMarkStackListNode* node) { return; } + // Order the hazard pointers loads w.r.t. the unlinking of the head node. + OrderAccess::fence(); + ZPerWorkerIterator iter(&_worker_states); ZArray* const scanned_hazards = &local_state->_scanned_hazards; From addf58309f323e6835aabc38dc2c82ccdf7ad88a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 26 Aug 2026 10:57:15 +0000 Subject: [PATCH 086/223] 8390937: G1: Iterating FullCardSet containers in test API only iterates over the first entry Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CardSet.cpp | 2 +- test/hotspot/gtest/gc/g1/test_g1CardSet.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index f0db638a2fed..0f66e739362f 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -967,7 +967,7 @@ class G1ContainerCardsClosure { void operator()(uint card_idx, uint length) { for (uint i = 0; i < length; i++) { - _cl.do_card(_region_idx, card_idx); + _cl.do_card(_region_idx, card_idx + i); } } }; diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index c2de96bea4fd..f3fb298ad346 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -46,6 +46,19 @@ class G1CardSetTest : public ::testing::Test { } }; + // Verify Full card containers contents (and amount). Assumes that cards returned are in ascending order. + class G1VerifyFullCardContainerClosure : public G1CardSet::CardClosure { + public: + size_t _cur_card; + + G1VerifyFullCardContainerClosure() : _cur_card(0) { } + + void do_card(uint region_idx, uint card_idx) override { + ASSERT_TRUE(card_idx == _cur_card); + _cur_card++; + } + }; + static WorkerThreads* _workers; static uint _max_workers; @@ -374,9 +387,9 @@ void G1CardSetTest::cardset_basic_test() { res = card_set.add_card(99, CardsPerRegion - 2); ASSERT_TRUE(res == Found); - G1CountCardsClosure count_cards; + G1VerifyFullCardContainerClosure count_cards; card_set.iterate_cards(count_cards); - ASSERT_TRUE(count_cards._num_cards == config.max_cards_in_region()); + ASSERT_TRUE(count_cards._cur_card == config.max_cards_in_region()); card_set.clear(); ASSERT_TRUE(card_set.occupied() == 0); From 64b67f6a967d05ca41da3cef611269cba39db268 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 26 Aug 2026 10:57:32 +0000 Subject: [PATCH 087/223] 8390940: G1: Retained region selection may take more than minimum regions Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index ca32759b54d3..a30386b38763 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -538,7 +538,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) double predicted_initial_time_ms = 0.0; double predicted_optional_time_ms = 0.0; - uint const min_regions = _policy->min_retained_old_cset_length(); + uint const min_num_regions = _policy->min_retained_old_cset_length(); // We want to make sure that on the one hand we process the retained regions asap, // but on the other hand do not take too many of them as optional regions. // So we split the time budget into budget we will unconditionally take into the @@ -552,7 +552,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " "Min %u regions, available %u regions (%u groups), " "time remaining %1.2fms, optional remaining %1.2fms", - min_regions, retained_groups->num_regions(), retained_groups->length(), + min_num_regions, retained_groups->num_regions(), retained_groups->length(), time_remaining_ms, optional_time_remaining_ms); G1CSetCandidateGroupList remove_from_retained; @@ -585,10 +585,10 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) continue; } - if (fits_in_remaining_time || (num_expensive_regions < min_regions)) { + if (num_initial_regions < min_num_regions || fits_in_remaining_time) { predicted_initial_time_ms += predicted_time_ms; if (!fits_in_remaining_time) { - num_expensive_regions++; + num_expensive_regions += group->length(); } add_group_to_collection_set(group); From cf3e413711d324a04d1db8d7cf189e0ee1dbaa25 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Wed, 26 Aug 2026 11:20:36 +0000 Subject: [PATCH 088/223] 8300944: Test vmTestbase/gc/gctests/WeakReference/weak005/weak005.java fails with "Last weak reference has not been cleared" Reviewed-by: aboldtch, lmesnik --- .../gctests/WeakReference/weak005/weak005.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak005/weak005.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak005/weak005.java index c1593aea9799..9895204e8e86 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak005/weak005.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak005/weak005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ import jdk.test.whitebox.WhiteBox; import nsk.share.gc.*; +import java.lang.ref.Reference; import java.lang.ref.WeakReference; /** @@ -56,23 +57,24 @@ class Worker implements Runnable { private int length = 10000; private int objectSize = 10000; private WeakReference[] references; + private WeakReference lastReference; public Worker() { System.out.println("Array size: " + length); System.out.println("Object size: " + objectSize); - references = new WeakReference[length]; } private void makeReferences() { - references[length - 1] = null; MemoryObject obj = new MemoryObject(objectSize); + references = new WeakReference[length]; references[0] = new WeakReference(obj); for (int i = 1; i < length; ++i) { references[i] = new WeakReference(references[i - 1]); } - for (int i = 0; i < length - 1; ++i) { - references[i] = null; - } + lastReference = references[length - 1]; + // Drop all strong references to the chain in one write. + references = null; + Reference.reachabilityFence(obj); } public void run() { @@ -81,7 +83,7 @@ public void run() { if (!getExecutionController().continueExecution()) { return; } - if (references[length - 1].get() != null) { + if (lastReference.get() != null) { log.error("Last weak reference has not been cleared"); setFailed(true); } From 284e0f8daf8187d24af04cb2eb35adc3c9fc706d Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Wed, 26 Aug 2026 15:24:13 +0000 Subject: [PATCH 089/223] 8388793: Convert test/jdk/java/foreign tests to use JUnit Reviewed-by: pminborg --- .../jdk/java/foreign/CallGeneratorHelper.java | 9 +- .../jdk/java/foreign/CompositeLookupTest.java | 20 +- test/jdk/java/foreign/LibraryLookupTest.java | 38 +-- .../MemoryLayoutPrincipalTotalityTest.java | 19 +- .../MemoryLayoutTypeRetentionTest.java | 19 +- .../java/foreign/SafeFunctionAccessTest.java | 31 ++- .../jdk/java/foreign/Test4BAlignedDouble.java | 11 +- test/jdk/java/foreign/TestAccessModes.java | 24 +- .../jdk/java/foreign/TestAdaptVarHandles.java | 247 +++++++++++------- .../java/foreign/TestAddressDereference.java | 36 +-- test/jdk/java/foreign/TestArrayCopy.java | 80 ++++-- test/jdk/java/foreign/TestArrays.java | 43 +-- test/jdk/java/foreign/TestByteBuffer.java | 214 ++++++++------- .../foreign/TestClassLoaderFindNative.java | 11 +- .../jdk/java/foreign/TestConcurrentClose.java | 7 +- .../jdk/java/foreign/TestDereferencePath.java | 54 ++-- test/jdk/java/foreign/TestDowncallBase.java | 5 +- test/jdk/java/foreign/TestDowncallScope.java | 18 +- test/jdk/java/foreign/TestDowncallStack.java | 16 +- test/jdk/java/foreign/TestFallbackLookup.java | 9 +- test/jdk/java/foreign/TestFree.java | 8 +- .../java/foreign/TestFunctionDescriptor.java | 68 +++-- test/jdk/java/foreign/TestHFA.java | 27 +- test/jdk/java/foreign/TestHandshake.java | 23 +- test/jdk/java/foreign/TestHeapAlignment.java | 16 +- test/jdk/java/foreign/TestIllegalLink.java | 54 ++-- test/jdk/java/foreign/TestIntrinsics.java | 18 +- .../java/foreign/TestLargeSegmentCopy.java | 7 +- test/jdk/java/foreign/TestLayoutPaths.java | 176 ++++++++----- test/jdk/java/foreign/TestLayouts.java | 176 ++++++++----- test/jdk/java/foreign/TestLinker.java | 85 +++--- .../jdk/java/foreign/TestMappedHandshake.java | 15 +- test/jdk/java/foreign/TestMatrix.java | 44 ++-- test/jdk/java/foreign/TestMemoryAccess.java | 79 +++--- .../foreign/TestMemoryAccessInstance.java | 56 ++-- .../jdk/java/foreign/TestMemoryAlignment.java | 61 +++-- .../java/foreign/TestMemoryDereference.java | 20 +- test/jdk/java/foreign/TestMemorySession.java | 55 ++-- test/jdk/java/foreign/TestMismatch.java | 152 ++++++----- test/jdk/java/foreign/TestNULLAddress.java | 24 +- test/jdk/java/foreign/TestNative.java | 42 +-- test/jdk/java/foreign/TestNulls.java | 24 +- test/jdk/java/foreign/TestOfBufferIssue.java | 8 +- test/jdk/java/foreign/TestReshape.java | 44 ++-- test/jdk/java/foreign/TestRestricted.java | 10 +- test/jdk/java/foreign/TestScope.java | 30 +-- .../java/foreign/TestScopedOperations.java | 28 +- .../java/foreign/TestSegmentAllocators.java | 136 +++++++--- test/jdk/java/foreign/TestSegmentCopy.java | 89 ++++--- test/jdk/java/foreign/TestSegmentOverlap.java | 47 ++-- test/jdk/java/foreign/TestSegments.java | 203 +++++++------- test/jdk/java/foreign/TestSharedAccess.java | 17 +- test/jdk/java/foreign/TestSlices.java | 81 +++--- test/jdk/java/foreign/TestSpliterator.java | 85 +++--- test/jdk/java/foreign/TestStringEncoding.java | 107 ++++---- .../java/foreign/TestStringEncodingJumbo.java | 11 +- .../java/foreign/TestStubAllocFailure.java | 9 +- test/jdk/java/foreign/TestTypeAccess.java | 48 ++-- test/jdk/java/foreign/TestUpcallAsync.java | 13 +- test/jdk/java/foreign/TestUpcallBase.java | 5 +- .../jdk/java/foreign/TestUpcallException.java | 15 +- .../jdk/java/foreign/TestUpcallHighArity.java | 15 +- test/jdk/java/foreign/TestUpcallScope.java | 13 +- test/jdk/java/foreign/TestUpcallStack.java | 13 +- test/jdk/java/foreign/TestUpcallStress.java | 21 +- .../java/foreign/TestUpcallStructScope.java | 16 +- test/jdk/java/foreign/TestValueLayouts.java | 17 +- test/jdk/java/foreign/TestVarArgs.java | 15 +- .../foreign/TestVarHandleCombinators.java | 32 +-- test/jdk/java/foreign/UpcallTestHelper.java | 4 +- .../arraystructs/TestArrayStructs.java | 17 +- .../callarranger/CallArrangerTestBase.java | 10 +- .../callarranger/TestLayoutEquality.java | 24 +- .../TestLinuxAArch64CallArranger.java | 69 ++--- .../TestMacOsAArch64CallArranger.java | 42 +-- .../callarranger/TestRISCV64CallArranger.java | 77 +++--- .../callarranger/TestSysVCallArranger.java | 93 +++---- .../TestWindowsAArch64CallArranger.java | 54 ++-- .../callarranger/TestWindowsCallArranger.java | 56 ++-- .../TestCaptureCallState.java | 32 ++- .../channels/AbstractChannelsTest.java | 12 +- .../channels/TestAsyncSocketChannels.java | 55 ++-- .../foreign/channels/TestSocketChannels.java | 80 +++--- .../java/foreign/critical/TestCritical.java | 25 +- .../foreign/critical/TestCriticalUpcall.java | 8 +- .../foreign/dontrelease/TestDontRelease.java | 9 +- .../TestEnableNativeAccess.java | 20 +- .../TestEnableNativeAccessBase.java | 4 +- .../TestEnableNativeAccessDynamic.java | 22 +- .../TestEnableNativeAccessJarManifest.java | 12 +- test/jdk/java/foreign/handles/Driver.java | 4 +- .../handle/lookup/MethodHandleLookup.java | 11 +- .../handles/lookup_module/module-info.java | 4 +- .../loaderLookup/TestLoaderLookupJNI.java | 8 +- .../TestSymbolLookupFindOrThrow.java | 7 +- test/jdk/java/foreign/nested/TestNested.java | 15 +- .../java/foreign/normalize/TestNormalize.java | 29 +- .../TestNormalizeBooleanVarHandle.java | 17 +- .../passheapsegment/TestPassHeapSegment.java | 35 ++- .../foreign/virtual/TestVirtualCalls.java | 22 +- 100 files changed, 2378 insertions(+), 1768 deletions(-) diff --git a/test/jdk/java/foreign/CallGeneratorHelper.java b/test/jdk/java/foreign/CallGeneratorHelper.java index 6fd32eac4109..1854d00c4a8f 100644 --- a/test/jdk/java/foreign/CallGeneratorHelper.java +++ b/test/jdk/java/foreign/CallGeneratorHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,10 @@ import java.util.stream.Stream; import jdk.internal.foreign.Utils; -import org.testng.annotations.*; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CallGeneratorHelper extends NativeTestHelper { static final List STACK_PREFIX_LAYOUTS = Stream.concat( @@ -151,7 +153,6 @@ static void generateTest(int i, Stack combo, Z[] elems, List> res } } - @DataProvider(name = "functions") public static Object[][] functions() { int functions = 0; List downcalls = new ArrayList<>(); @@ -209,7 +210,7 @@ private static PrintStream printStream(String first) throws IOException { // This can be used to generate the test implementation. // From the test/jdk/java/foreign directory, run this class using: - // java -cp \lib\testng-7.3.0.jar --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED ./CallGeneratorHelper.java + // java -cp /lib/junit-platform-console-standalone-1.14.2.jar --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED ./CallGeneratorHelper.java // Copyright header has to be added manually, and on Windows line endings have to be changed from \r\n to just \n public static void main(String[] args) throws IOException { try (PrintStream shared = printStream("shared.h"); diff --git a/test/jdk/java/foreign/CompositeLookupTest.java b/test/jdk/java/foreign/CompositeLookupTest.java index 1cc0b35950d3..a3c34ea9e8e7 100644 --- a/test/jdk/java/foreign/CompositeLookupTest.java +++ b/test/jdk/java/foreign/CompositeLookupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,36 +21,39 @@ * questions. */ -import org.testng.annotations.Test; import java.lang.foreign.*; import java.util.List; import java.util.Optional; import java.util.Set; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test - * @run testng CompositeLookupTest + * @run junit CompositeLookupTest */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CompositeLookupTest { - @Test(dataProvider = "testCases") + @ParameterizedTest + @MethodSource("testCases") public void testLookups(SymbolLookup lookup, List results) { for (Result result : results) { switch (result) { case Success(String name, long expectedLookupId) -> { Optional symbol = lookup.find(name); assertTrue(symbol.isPresent()); - assertEquals(symbol.get().address(), expectedLookupId); + assertEquals(expectedLookupId, symbol.get().address()); } case Failure(String name) -> { Optional symbol = lookup.find(name); assertFalse(symbol.isPresent()); } + } } } @@ -76,7 +79,6 @@ sealed interface Result { } record Success(String name, long expectedLookupId) implements Result { } record Failure(String name) implements Result { } - @DataProvider(name = "testCases") public Object[][] testCases() { return new Object[][]{ { diff --git a/test/jdk/java/foreign/LibraryLookupTest.java b/test/jdk/java/foreign/LibraryLookupTest.java index ad2f02c5df3f..8c71c2286549 100644 --- a/test/jdk/java/foreign/LibraryLookupTest.java +++ b/test/jdk/java/foreign/LibraryLookupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,6 @@ * questions. */ -import org.testng.annotations.Test; import java.io.IOException; import java.lang.foreign.*; @@ -37,11 +36,12 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /* * @test id=specialized - * @run testng/othervm/native + * @run junit/othervm/native * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * --enable-native-access=ALL-UNNAMED * LibraryLookupTest @@ -49,7 +49,7 @@ /* * @test id=interpreted - * @run testng/othervm/native + * @run junit/othervm/native * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * --enable-native-access=ALL-UNNAMED * LibraryLookupTest @@ -73,19 +73,23 @@ void testLoadLibraryConfined() { } } - @Test(expectedExceptions = IllegalStateException.class) + @Test void testLoadLibraryConfinedClosed() { MemorySegment addr; try (Arena arena = Arena.ofConfined()) { addr = loadLibrary(arena); } - callFunc(addr); + assertThrows(IllegalStateException.class, () -> { + callFunc(addr); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testLoadLibraryBadName() { try (Arena arena = Arena.ofConfined()) { - SymbolLookup.libraryLookup(LIB_PATH.toString() + "\u0000", arena); + assertThrows(IllegalArgumentException.class, () -> { + SymbolLookup.libraryLookup(LIB_PATH.toString() + "\u0000", arena); + }); } } @@ -99,7 +103,7 @@ void testLoadLibraryBadLookupName() { @Test void testLoadLibraryNonDefaultFileSystem() throws URISyntaxException, IOException { - try (FileSystem customFs = fsFromJarOfClass(org.testng.annotations.Test.class)) { + try (FileSystem customFs = fsFromJarOfClass(Test.class)) { try (Arena arena = Arena.ofConfined()) { Path p = customFs.getPath("."); try { @@ -131,7 +135,7 @@ private static FileSystem fsFromJarOfClass(Class clazz) throws URISyntaxExcep private static MemorySegment loadLibrary(Arena session) { SymbolLookup lib = SymbolLookup.libraryLookup(LIB_PATH, session); MemorySegment addr = lib.find("inc").get(); - assertEquals(addr.scope(), session.scope()); + assertEquals(session.scope(), addr.scope()); return addr; } @@ -149,14 +153,18 @@ private static void callFunc(MemorySegment addr) { static final int MAX_EXECUTOR_WAIT_SECONDS = 20; static final int NUM_ACCESSORS = Math.min(10, Runtime.getRuntime().availableProcessors()); - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testBadLibraryLookupName() { - SymbolLookup.libraryLookup("nonExistent", Arena.global()); + assertThrows(IllegalArgumentException.class, () -> { + SymbolLookup.libraryLookup("nonExistent", Arena.global()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testBadLibraryLookupPath() { - SymbolLookup.libraryLookup(Path.of("nonExistent"), Arena.global()); + assertThrows(IllegalArgumentException.class, () -> { + SymbolLookup.libraryLookup(Path.of("nonExistent"), Arena.global()); + }); } @Test diff --git a/test/jdk/java/foreign/MemoryLayoutPrincipalTotalityTest.java b/test/jdk/java/foreign/MemoryLayoutPrincipalTotalityTest.java index c304a1390148..0ffd43ef6ddd 100644 --- a/test/jdk/java/foreign/MemoryLayoutPrincipalTotalityTest.java +++ b/test/jdk/java/foreign/MemoryLayoutPrincipalTotalityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,16 @@ /* * @test - * @run testng/othervm MemoryLayoutPrincipalTotalityTest + * @run junit/othervm MemoryLayoutPrincipalTotalityTest */ -import org.testng.annotations.*; import java.lang.foreign.*; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class MemoryLayoutPrincipalTotalityTest { @@ -43,7 +44,7 @@ public void testBasicTotality() { int v0 = switch (memoryLayout) { case MemoryLayout ml -> 1; }; - assertEquals(v0, 1); + assertEquals(1, v0); } @Test @@ -55,7 +56,7 @@ public void testMLRemovedTotality() { case SequenceLayout sl -> 0; // leaf case ValueLayout vl -> 1; }; - assertEquals(v1, 1); + assertEquals(1, v1); } @Test @@ -68,7 +69,7 @@ public void testMLGLRemovedTotality() { case StructLayout sl -> 0; // leaf case UnionLayout ul -> 0; // leaf }; - assertEquals(v2, 1); + assertEquals(1, v2); } @Test @@ -89,7 +90,7 @@ public void testMLGLVLRemovedTotality() { case OfLong ol -> 0; // leaf case OfShort os -> 0; // leaf }; - assertEquals(v3, 1); + assertEquals(1, v3); } @Test @@ -109,7 +110,7 @@ public void testMLVLRemovedTotality() { case OfLong ol -> 0; // leaf case OfShort os -> 0; // leaf }; - assertEquals(v4, 1); + assertEquals(1, v4); } private static MemoryLayout javaIntMemoryLayout() { diff --git a/test/jdk/java/foreign/MemoryLayoutTypeRetentionTest.java b/test/jdk/java/foreign/MemoryLayoutTypeRetentionTest.java index ecfc4b0da38a..12f9b1451334 100644 --- a/test/jdk/java/foreign/MemoryLayoutTypeRetentionTest.java +++ b/test/jdk/java/foreign/MemoryLayoutTypeRetentionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,17 @@ /* * @test - * @run testng/othervm MemoryLayoutTypeRetentionTest + * @run junit/othervm MemoryLayoutTypeRetentionTest */ -import org.testng.annotations.*; import java.lang.foreign.*; import java.nio.ByteOrder; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class MemoryLayoutTypeRetentionTest { @@ -144,12 +145,12 @@ public void testAddressLayout() { .withoutTargetLayout() .withOrder(BYTE_ORDER); check(v); - assertEquals(v.order(), BYTE_ORDER); + assertEquals(BYTE_ORDER, v.order()); assertFalse(v.targetLayout().isPresent()); AddressLayout v2 = v.withTargetLayout(JAVA_INT); assertTrue(v2.targetLayout().isPresent()); - assertEquals(v2.targetLayout().get(), JAVA_INT); + assertEquals(JAVA_INT, v2.targetLayout().get()); assertTrue(v2.withoutTargetLayout().targetLayout().isEmpty()); } @@ -197,15 +198,15 @@ public void testUnionLayout() { public void check(ValueLayout v) { check((MemoryLayout) v); - assertEquals(v.order(), BYTE_ORDER); + assertEquals(BYTE_ORDER, v.order()); } public void check(MemoryLayout v) { // Check name properties - assertEquals(v.name().orElseThrow(), NAME); + assertEquals(NAME, v.name().orElseThrow()); assertTrue(v.withoutName().name().isEmpty()); - assertEquals(v.byteAlignment(), BYTE_ALIGNMENT); + assertEquals(BYTE_ALIGNMENT, v.byteAlignment()); } } diff --git a/test/jdk/java/foreign/SafeFunctionAccessTest.java b/test/jdk/java/foreign/SafeFunctionAccessTest.java index 658a0bfc7848..23ca75c3e2ec 100644 --- a/test/jdk/java/foreign/SafeFunctionAccessTest.java +++ b/test/jdk/java/foreign/SafeFunctionAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test id=specialized - * @run testng/othervm/native + * @run junit/othervm/native * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * --enable-native-access=ALL-UNNAMED * SafeFunctionAccessTest @@ -31,7 +31,7 @@ /* * @test id=interpreted - * @run testng/othervm/native + * @run junit/othervm/native * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * --enable-native-access=ALL-UNNAMED * SafeFunctionAccessTest @@ -49,9 +49,8 @@ import java.util.stream.Stream; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class SafeFunctionAccessTest extends NativeTestHelper { static { @@ -62,18 +61,18 @@ public class SafeFunctionAccessTest extends NativeTestHelper { C_INT, C_INT ); - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testClosedStruct() throws Throwable { MemorySegment segment; try (Arena arena = Arena.ofConfined()) { segment = arena.allocate(POINT); - } - assertFalse(segment.scope().isAlive()); + } assertFalse(segment.scope().isAlive()); MethodHandle handle = Linker.nativeLinker().downcallHandle( findNativeOrThrow("struct_func"), FunctionDescriptor.ofVoid(POINT)); - - handle.invokeExact(segment); + assertThrows(IllegalStateException.class, () -> { + handle.invokeExact(segment); + }); } @Test @@ -119,19 +118,19 @@ static Allocation of(MemoryLayout layout) { } } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testClosedUpcall() throws Throwable { MemorySegment upcall; try (Arena arena = Arena.ofConfined()) { MethodHandle dummy = MethodHandles.lookup().findStatic(SafeFunctionAccessTest.class, "dummy", MethodType.methodType(void.class)); upcall = Linker.nativeLinker().upcallStub(dummy, FunctionDescriptor.ofVoid(), arena); - } - assertFalse(upcall.scope().isAlive()); + } assertFalse(upcall.scope().isAlive()); MethodHandle handle = Linker.nativeLinker().downcallHandle( findNativeOrThrow("addr_func"), FunctionDescriptor.ofVoid(C_POINTER)); - - handle.invokeExact(upcall); + assertThrows(IllegalStateException.class, () -> { + handle.invokeExact(upcall); + }); } static void dummy() { } diff --git a/test/jdk/java/foreign/Test4BAlignedDouble.java b/test/jdk/java/foreign/Test4BAlignedDouble.java index ce3bf6c5f2f8..958257e8c459 100644 --- a/test/jdk/java/foreign/Test4BAlignedDouble.java +++ b/test/jdk/java/foreign/Test4BAlignedDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,17 +26,18 @@ * @test * @summary Test passing of a structure which contains a double with 4 Byte alignment on AIX. * - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED Test4BAlignedDouble + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED Test4BAlignedDouble */ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.*; +import org.junit.jupiter.api.Test; + public class Test4BAlignedDouble { static { @@ -82,7 +83,7 @@ public class Test4BAlignedDouble { FunctionDescriptor.of(platform_S_IDFLayout, ADDRESS, platform_S_IDFLayout)); @Test - public static void testDowncall() { + public void testDowncall() { int p0 = 0; double p1 = 0.0d; float p2 = 0.0f; @@ -113,7 +114,7 @@ public static MemorySegment S_IDF_fun(MemorySegment p) { } @Test - public static void testUpcall() { + public void testUpcall() { int p0 = 0; double p1 = 0.0d; float p2 = 0.0f; diff --git a/test/jdk/java/foreign/TestAccessModes.java b/test/jdk/java/foreign/TestAccessModes.java index e54d4f1ae9ed..9bce17d679ed 100644 --- a/test/jdk/java/foreign/TestAccessModes.java +++ b/test/jdk/java/foreign/TestAccessModes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,10 @@ /* * @test - * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes - * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run junit/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run junit/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run junit/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run junit/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes */ import java.lang.foreign.*; @@ -40,12 +40,15 @@ import java.util.List; import java.util.Set; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestAccessModes { - @Test(dataProvider = "segmentsAndLayoutsAndModes") + @ParameterizedTest + @MethodSource("segmentsAndLayoutsAndModes") public void testAccessModes(MemorySegment segment, MemoryLayout layout, AccessMode mode) throws Throwable { VarHandle varHandle = layout instanceof ValueLayout ? layout.varHandle() : @@ -61,7 +64,7 @@ public void testAccessModes(MemorySegment segment, MemoryLayout layout, AccessMo // access is unaligned assertTrue(segment.maxByteAlignment() < layout.byteAlignment()); } - assertEquals(varHandle.isAccessModeSupported(mode), compatible); + assertEquals(compatible, varHandle.isAccessModeSupported(mode)); } static ValueLayout accessLayout(MemoryLayout layout) { @@ -171,7 +174,6 @@ static MemorySegment[] segments() { }; } - @DataProvider(name = "segmentsAndLayoutsAndModes") static Object[][] segmentsAndLayoutsAndModes() { List segmentsAndLayouts = new ArrayList<>(); for (MemorySegment segment : segments()) { diff --git a/test/jdk/java/foreign/TestAdaptVarHandles.java b/test/jdk/java/foreign/TestAdaptVarHandles.java index ebbef0ffb6bc..9977329166dd 100644 --- a/test/jdk/java/foreign/TestAdaptVarHandles.java +++ b/test/jdk/java/foreign/TestAdaptVarHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,15 @@ /* * @test - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAdaptVarHandles - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAdaptVarHandles + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAdaptVarHandles + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAdaptVarHandles */ import java.lang.foreign.*; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -41,6 +40,8 @@ import java.lang.invoke.VarHandle; import java.util.List; +import org.junit.jupiter.api.Test; + public class TestAdaptVarHandles { static MethodHandle S2I; @@ -98,15 +99,15 @@ public void testFilterValue() throws Throwable { VarHandle i2SHandle = MethodHandles.filterValue(intHandle, S2I, I2S); i2SHandle.set(segment, 0L, "1"); String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42"); - assertEquals(oldValue, "1"); + assertEquals("1", oldValue); String value = (String)i2SHandle.get(segment, 0L); - assertEquals(value, "43"); + assertEquals("43", value); boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12"); assertTrue(swapped); oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42"); - assertEquals(oldValue, "12"); + assertEquals("12", oldValue); value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L); - assertEquals(value, "42"); + assertEquals("42", value); } @Test @@ -120,15 +121,15 @@ public void testFilterValueComposite() throws Throwable { i2SHandle = MethodHandles.insertCoordinates(i2SHandle, 2, "a", "b"); i2SHandle.set(segment, 0L, "1"); String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42"); - assertEquals(oldValue, "ab1"); + assertEquals("ab1", oldValue); String value = (String)i2SHandle.get(segment, 0L); - assertEquals(value, "ab43"); + assertEquals("ab43", value); boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12"); assertTrue(swapped); oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42"); - assertEquals(oldValue, "ab12"); + assertEquals("ab12", oldValue); value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L); - assertEquals(value, "ab42"); + assertEquals("ab42", value); } @Test @@ -140,72 +141,88 @@ public void testFilterValueLoose() throws Throwable { VarHandle i2SHandle = MethodHandles.filterValue(intHandle, O2I, I2O); i2SHandle.set(segment, 0L, "1"); String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42"); - assertEquals(oldValue, "1"); + assertEquals("1", oldValue); String value = (String)i2SHandle.get(segment, 0L); - assertEquals(value, "43"); + assertEquals("43", value); boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12"); assertTrue(swapped); oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42"); - assertEquals(oldValue, "12"); + assertEquals("12", oldValue); value = (String)(Object)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L); - assertEquals(value, "42"); + assertEquals("42", value); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCarrier() { - MethodHandles.filterValue(floatHandle, S2I, I2S); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(floatHandle, S2I, I2S); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterUnboxArity() { VarHandle floatHandle = ValueLayout.JAVA_INT.varHandle(); - MethodHandles.filterValue(floatHandle, S2I.bindTo(""), I2S); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(floatHandle, S2I.bindTo(""), I2S); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterBoxArity() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); - MethodHandles.filterValue(intHandle, S2I, I2S.bindTo(42)); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(intHandle, S2I, I2S.bindTo(42)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterBoxPrefixCoordinates() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); - MethodHandles.filterValue(intHandle, - MethodHandles.dropArguments(S2I, 1, int.class), - MethodHandles.dropArguments(I2S, 1, long.class)); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(intHandle, + MethodHandles.dropArguments(S2I, 1, int.class), + MethodHandles.dropArguments(I2S, 1, long.class)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterBoxException() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); - MethodHandles.filterValue(intHandle, I2S, S2L_EX); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(intHandle, I2S, S2L_EX); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterUnboxException() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); - MethodHandles.filterValue(intHandle, S2L_EX, I2S); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterValue(intHandle, S2L_EX, I2S); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testBadFilterBoxHandleException() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); VarHandle vh = MethodHandles.filterValue(intHandle, S2I, I2S_EX); try (Arena arena = Arena.ofConfined()) { MemorySegment seg = arena.allocate(ValueLayout.JAVA_INT); vh.set(seg, 0L, "42"); - String x = (String) vh.get(seg, 0L); // should throw + assertThrows(IllegalStateException.class, () -> { + String x = (String) vh.get(seg, 0L); + }); } } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testBadFilterUnboxHandleException() { VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); VarHandle vh = MethodHandles.filterValue(intHandle, S2I_EX, I2S); try (Arena arena = Arena.ofConfined()) { MemorySegment seg = arena.allocate(ValueLayout.JAVA_INT); - vh.set(seg, 0L, "42"); // should throw + assertThrows(IllegalStateException.class, () -> { + vh.set(seg, 0L, "42"); // should throw + }); } } @@ -217,40 +234,50 @@ public void testFilterCoordinates() throws Throwable { VarHandle intHandle_longIndex = MethodHandles.filterCoordinates(intHandleIndexed, 0, BASE_ADDR, S2L); intHandle_longIndex.set(segment, "0", 1); int oldValue = (int)intHandle_longIndex.getAndAdd(segment, "0", 42); - assertEquals(oldValue, 1); + assertEquals(1, oldValue); int value = (int)intHandle_longIndex.get(segment, "0"); - assertEquals(value, 43); + assertEquals(43, value); boolean swapped = (boolean)intHandle_longIndex.compareAndSet(segment, "0", 43, 12); assertTrue(swapped); oldValue = (int)intHandle_longIndex.compareAndExchange(segment, "0", 12, 42); - assertEquals(oldValue, 12); + assertEquals(12, oldValue); value = (int)intHandle_longIndex.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, "0"); - assertEquals(value, 42); + assertEquals(42, value); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCoordinatesNegativePos() { - MethodHandles.filterCoordinates(intHandle, -1, SUM_OFFSETS); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterCoordinates(intHandle, -1, SUM_OFFSETS); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCoordinatesPosTooBig() { - MethodHandles.filterCoordinates(intHandle, 1, SUM_OFFSETS); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterCoordinates(intHandle, 1, SUM_OFFSETS); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCoordinatesWrongFilterType() { - MethodHandles.filterCoordinates(intHandleIndexed, 1, S2I); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterCoordinates(intHandleIndexed, 1, S2I); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCoordinatesWrongFilterException() { - MethodHandles.filterCoordinates(intHandleIndexed, 1, S2L_EX); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterCoordinates(intHandleIndexed, 1, S2L_EX); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadFilterCoordinatesTooManyFilters() { - MethodHandles.filterCoordinates(intHandleIndexed, 1, S2L, S2L); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.filterCoordinates(intHandleIndexed, 1, S2L, S2L); + }); } @Test @@ -261,35 +288,43 @@ public void testInsertCoordinates() throws Throwable { VarHandle intHandle_longIndex = MethodHandles.insertCoordinates(intHandleIndexed, 0, segment, 0L); intHandle_longIndex.set(1); int oldValue = (int)intHandle_longIndex.getAndAdd(42); - assertEquals(oldValue, 1); + assertEquals(1, oldValue); int value = (int)intHandle_longIndex.get(); - assertEquals(value, 43); + assertEquals(43, value); boolean swapped = (boolean)intHandle_longIndex.compareAndSet(43, 12); assertTrue(swapped); oldValue = (int)intHandle_longIndex.compareAndExchange(12, 42); - assertEquals(oldValue, 12); + assertEquals(12, oldValue); value = (int)intHandle_longIndex.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(); - assertEquals(value, 42); + assertEquals(42, value); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadInsertCoordinatesNegativePos() { - MethodHandles.insertCoordinates(intHandle, -1, 42); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.insertCoordinates(intHandle, -1, 42); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadInsertCoordinatesPosTooBig() { - MethodHandles.insertCoordinates(intHandle, 1, 42); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.insertCoordinates(intHandle, 1, 42); + }); } - @Test(expectedExceptions = ClassCastException.class) + @Test public void testBadInsertCoordinatesWrongCoordinateType() { - MethodHandles.insertCoordinates(intHandleIndexed, 1, "Hello"); + assertThrows(ClassCastException.class, () -> { + MethodHandles.insertCoordinates(intHandleIndexed, 1, "Hello"); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadInsertCoordinatesTooManyValues() { - MethodHandles.insertCoordinates(intHandleIndexed, 1, 0L, 0L); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.insertCoordinates(intHandleIndexed, 1, 0L, 0L); + }); } @Test @@ -301,35 +336,43 @@ public void testPermuteCoordinates() throws Throwable { List.of(long.class, MemorySegment.class), 1, 0); intHandle_swap.set(0L, segment, 1); int oldValue = (int)intHandle_swap.getAndAdd(0L, segment, 42); - assertEquals(oldValue, 1); + assertEquals(1, oldValue); int value = (int)intHandle_swap.get(0L, segment); - assertEquals(value, 43); + assertEquals(43, value); boolean swapped = (boolean)intHandle_swap.compareAndSet(0L, segment, 43, 12); assertTrue(swapped); oldValue = (int)intHandle_swap.compareAndExchange(0L, segment, 12, 42); - assertEquals(oldValue, 12); + assertEquals(12, oldValue); value = (int)intHandle_swap.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(0L, segment); - assertEquals(value, 42); + assertEquals(42, value); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPermuteCoordinatesTooManyCoordinates() { - MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), new int[2]); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), new int[2]); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPermuteCoordinatesTooFewCoordinates() { - MethodHandles.permuteCoordinates(intHandle, List.of()); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.permuteCoordinates(intHandle, List.of()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPermuteCoordinatesIndexTooBig() { - MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), 3); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), 3); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPermuteCoordinatesIndexTooSmall() { - MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), -1); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), -1); + }); } @Test @@ -340,41 +383,49 @@ public void testCollectCoordinates() throws Throwable { VarHandle intHandle_sum = MethodHandles.collectCoordinates(intHandleIndexed, 1, SUM_OFFSETS); intHandle_sum.set(segment, -2L, 2L, 1); int oldValue = (int)intHandle_sum.getAndAdd(segment, -2L, 2L, 42); - assertEquals(oldValue, 1); + assertEquals(1, oldValue); int value = (int)intHandle_sum.get(segment, -2L, 2L); - assertEquals(value, 43); + assertEquals(43, value); boolean swapped = (boolean)intHandle_sum.compareAndSet(segment, -2L, 2L, 43, 12); assertTrue(swapped); oldValue = (int)intHandle_sum.compareAndExchange(segment, -2L, 2L, 12, 42); - assertEquals(oldValue, 12); + assertEquals(12, oldValue); value = (int)intHandle_sum.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, -2L, 2L); - assertEquals(value, 42); + assertEquals(42, value); } @Test public void testCollectCoordinatesVoidFilterType() { VarHandle handle = MethodHandles.collectCoordinates(intHandle, 0, VOID_FILTER); - assertEquals(handle.coordinateTypes(), List.of(String.class, MemorySegment.class)); + assertEquals(List.of(String.class, MemorySegment.class), handle.coordinateTypes()); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadCollectCoordinatesNegativePos() { - MethodHandles.collectCoordinates(intHandle, -1, SUM_OFFSETS); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.collectCoordinates(intHandle, -1, SUM_OFFSETS); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadCollectCoordinatesPosTooBig() { - MethodHandles.collectCoordinates(intHandle, 1, SUM_OFFSETS); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.collectCoordinates(intHandle, 1, SUM_OFFSETS); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadCollectCoordinatesWrongFilterType() { - MethodHandles.collectCoordinates(intHandle, 0, SUM_OFFSETS); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.collectCoordinates(intHandle, 0, SUM_OFFSETS); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadCollectCoordinatesWrongFilterException() { - MethodHandles.collectCoordinates(intHandle, 0, S2L_EX); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.collectCoordinates(intHandle, 0, S2L_EX); + }); } @Test @@ -385,25 +436,29 @@ public void testDropCoordinates() throws Throwable { VarHandle intHandle_dummy = MethodHandles.dropCoordinates(intHandleIndexed, 1, float.class, String.class); intHandle_dummy.set(segment, 1f, "hello", 0L, 1); int oldValue = (int)intHandle_dummy.getAndAdd(segment, 1f, "hello", 0L, 42); - assertEquals(oldValue, 1); + assertEquals(1, oldValue); int value = (int)intHandle_dummy.get(segment, 1f, "hello", 0L); - assertEquals(value, 43); + assertEquals(43, value); boolean swapped = (boolean)intHandle_dummy.compareAndSet(segment, 1f, "hello", 0L, 43, 12); assertTrue(swapped); oldValue = (int)intHandle_dummy.compareAndExchange(segment, 1f, "hello", 0L, 12, 42); - assertEquals(oldValue, 12); + assertEquals(12, oldValue); value = (int)intHandle_dummy.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 1f, "hello", 0L); - assertEquals(value, 42); + assertEquals(42, value); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadDropCoordinatesNegativePos() { - MethodHandles.dropCoordinates(intHandle, -1); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.dropCoordinates(intHandle, -1); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadDropCoordinatesPosTooBig() { - MethodHandles.dropCoordinates(intHandle, 2); + assertThrows(IllegalArgumentException.class, () -> { + MethodHandles.dropCoordinates(intHandle, 2); + }); } //helper methods diff --git a/test/jdk/java/foreign/TestAddressDereference.java b/test/jdk/java/foreign/TestAddressDereference.java index 76ab0086eb93..c617060119e6 100644 --- a/test/jdk/java/foreign/TestAddressDereference.java +++ b/test/jdk/java/foreign/TestAddressDereference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @library ../ /test/lib - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestAddressDereference + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestAddressDereference */ import java.lang.foreign.Arena; @@ -41,10 +41,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestAddressDereference extends UpcallTestHelper { static final Linker LINKER = Linker.nativeLinker(); @@ -65,7 +67,8 @@ public class TestAddressDereference extends UpcallTestHelper { } } - @Test(dataProvider = "layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testGetAddress(long alignment, ValueLayout layout) { boolean badAlign = layout.byteAlignment() > alignment; try (Arena arena = Arena.ofConfined()) { @@ -73,14 +76,15 @@ public void testGetAddress(long alignment, ValueLayout layout) { segment.set(ValueLayout.ADDRESS, 0, MemorySegment.ofAddress(alignment)); MemorySegment deref = segment.get(ValueLayout.ADDRESS.withTargetLayout(layout), 0); assertFalse(badAlign); - assertEquals(deref.byteSize(), layout.byteSize()); + assertEquals(layout.byteSize(), deref.byteSize()); } catch (IllegalArgumentException ex) { assertTrue(badAlign); assertTrue(ex.getMessage().contains("alignment constraint for address")); } } - @Test(dataProvider = "layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testGetAddressIndex(long alignment, ValueLayout layout) { boolean badAlign = layout.byteAlignment() > alignment; try (Arena arena = Arena.ofConfined()) { @@ -88,14 +92,15 @@ public void testGetAddressIndex(long alignment, ValueLayout layout) { segment.set(ValueLayout.ADDRESS, 0, MemorySegment.ofAddress(alignment)); MemorySegment deref = segment.getAtIndex(ValueLayout.ADDRESS.withTargetLayout(layout), 0); assertFalse(badAlign); - assertEquals(deref.byteSize(), layout.byteSize()); + assertEquals(layout.byteSize(), deref.byteSize()); } catch (IllegalArgumentException ex) { assertTrue(badAlign); assertTrue(ex.getMessage().contains("alignment constraint for address")); } } - @Test(dataProvider = "layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testNativeReturn(long alignment, ValueLayout layout) throws Throwable { boolean badAlign = layout.byteAlignment() > alignment; try { @@ -103,14 +108,15 @@ public void testNativeReturn(long alignment, ValueLayout layout) throws Throwabl FunctionDescriptor.of(ValueLayout.ADDRESS.withTargetLayout(layout), ValueLayout.ADDRESS)); MemorySegment deref = (MemorySegment)get_addr_handle.invokeExact(MemorySegment.ofAddress(alignment)); assertFalse(badAlign); - assertEquals(deref.byteSize(), layout.byteSize()); + assertEquals(layout.byteSize(), deref.byteSize()); } catch (IllegalArgumentException ex) { assertTrue(badAlign); assertTrue(ex.getMessage().contains("alignment constraint for address")); } } - @Test(dataProvider = "layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testNativeUpcallArgPos(long alignment, ValueLayout layout) throws Throwable { boolean badAlign = layout.byteAlignment() > alignment; if (badAlign) return; // this will crash the JVM (exception occurs when going into the upcall stub) @@ -122,7 +128,8 @@ public void testNativeUpcallArgPos(long alignment, ValueLayout layout) throws Th } } - @Test(dataProvider = "layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testNativeUpcallArgNeg(long alignment, ValueLayout layout) throws Throwable { boolean badAlign = layout.byteAlignment() > alignment; if (!badAlign) return; @@ -154,10 +161,9 @@ static ValueLayout parseLayout(String s) { } static void testArg(MemorySegment deref, long expectedSize) { - assertEquals(deref.byteSize(), expectedSize); + assertEquals(expectedSize, deref.byteSize()); } - @DataProvider(name = "layoutsAndAlignments") static Object[][] layoutsAndAlignments() { List layoutsAndAlignments = new ArrayList<>(); for (LayoutKind lk : LayoutKind.values()) { diff --git a/test/jdk/java/foreign/TestArrayCopy.java b/test/jdk/java/foreign/TestArrayCopy.java index 9a1c48a394e0..b86bfe1266e3 100644 --- a/test/jdk/java/foreign/TestArrayCopy.java +++ b/test/jdk/java/foreign/TestArrayCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestArrayCopy + * @run junit TestArrayCopy */ import java.lang.foreign.MemorySegment; @@ -33,13 +33,15 @@ import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * These tests exercise the MemoryCopy copyFromArray(...) and copyToArray(...). @@ -51,6 +53,7 @@ * the copy of the overlapping region is performed as if the data in the overlapping region * were first copied into a temporary segment before being copied to the destination.

*/ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestArrayCopy { private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); private static final ByteOrder NON_NATIVE_ORDER = NATIVE_ORDER == ByteOrder.LITTLE_ENDIAN @@ -59,7 +62,8 @@ public class TestArrayCopy { private static final int SEG_LENGTH_BYTES = 32; private static final int SEG_OFFSET_BYTES = 8; - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testSelfCopy(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); int indexShifts = SEG_OFFSET_BYTES / bytesPerElement; @@ -73,7 +77,7 @@ public void testSelfCopy(CopyMode mode, CopyHelper helper, MemorySegment dstSeg = helper.fromArray(srcArr); long dstOffsetBytes = mode.direction ? SEG_OFFSET_BYTES : 0; helper.copyFromArray(srcArr, srcIndex, srcCopyLen, dstSeg, dstOffsetBytes, bo); - assertEquals(truth.mismatch(dstSeg), -1); + assertEquals(-1, truth.mismatch(dstSeg)); //CopyTo long srcOffsetBytes = mode.direction ? 0 : SEG_OFFSET_BYTES; Object dstArr = helper.toArray(base); @@ -82,10 +86,11 @@ public void testSelfCopy(CopyMode mode, CopyHelper helper, int dstCopyLen = helper.length(dstArr) - indexShifts; helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo); MemorySegment result = helper.fromArray(dstArr); - assertEquals(truth.mismatch(result), -1); + assertEquals(-1, truth.mismatch(result)); } - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testUnalignedCopy(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); int indexShifts = SEG_OFFSET_BYTES / bytesPerElement; @@ -107,7 +112,8 @@ public void testUnalignedCopy(CopyMode mode, CopyHelper hel helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo); } - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testCopyOobLength(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -131,7 +137,8 @@ public void testCopyOobLength(CopyMode mode, CopyHelper hel } } - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testCopyNegativeIndices(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -155,7 +162,8 @@ public void testCopyNegativeIndices(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -179,7 +187,8 @@ public void testCopyNegativeOffsets(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -203,7 +212,8 @@ public void testCopyOobIndices(CopyMode mode, CopyHelper he } } - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testCopyOobOffsets(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -227,7 +237,8 @@ public void testCopyOobOffsets(CopyMode mode, CopyHelper he } } - @Test(dataProvider = "copyModesAndHelpers") + @ParameterizedTest + @MethodSource("copyModesAndHelpers") public void testCopyReadOnlyDest(CopyMode mode, CopyHelper helper, String helperDebugString) { int bytesPerElement = (int)helper.elementLayout.byteSize(); MemorySegment base = srcSegment(SEG_LENGTH_BYTES); @@ -242,40 +253,52 @@ public void testCopyReadOnlyDest(CopyMode mode, CopyHelper } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNotAnArraySrc() { MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); - MemorySegment.copy(segment, JAVA_BYTE, 0, new String[] { "hello" }, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(segment, JAVA_BYTE, 0, new String[] { "hello" }, 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNotAnArrayDst() { MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); - MemorySegment.copy(new String[] { "hello" }, 0, segment, JAVA_BYTE, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(new String[] { "hello" }, 0, segment, JAVA_BYTE, 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testCarrierMismatchSrc() { MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); - MemorySegment.copy(segment, JAVA_INT, 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(segment, JAVA_INT, 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testCarrierMismatchDst() { MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4}); - MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_INT, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_INT, 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testHyperAlignedSrc() { MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); - MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testHyperAlignedDst() { MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); - MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, new byte[] { 1, 2, 3, 4 }, 0, 4); + }); } /***** Utilities *****/ @@ -555,7 +578,6 @@ int length(double[] arr) { }; } - @DataProvider Object[][] copyModesAndHelpers() { CopyHelper[] helpers = { CopyHelper.BYTE, CopyHelper.CHAR, CopyHelper.SHORT, CopyHelper.INT, CopyHelper.FLOAT, CopyHelper.LONG, CopyHelper.DOUBLE }; diff --git a/test/jdk/java/foreign/TestArrays.java b/test/jdk/java/foreign/TestArrays.java index 4406db36750d..2fb86caeba71 100644 --- a/test/jdk/java/foreign/TestArrays.java +++ b/test/jdk/java/foreign/TestArrays.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestArrays + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestArrays */ import java.lang.foreign.*; @@ -39,7 +39,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_CHAR; @@ -48,8 +47,13 @@ import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestArrays { static SequenceLayout bytes = MemoryLayout.sequenceLayout(100, @@ -104,7 +108,8 @@ static void checkBytes(MemorySegment base, SequenceLayout layout, Function init, Consumer checker, MemoryLayout layout) { Arena scope = Arena.ofAuto(); MemorySegment segment = scope.allocate(layout); @@ -113,37 +118,42 @@ public void testArrays(Consumer init, Consumer che checker.accept(segment); } - @Test(dataProvider = "elemLayouts", - expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("elemLayouts") public void testTooBigForArray(MemoryLayout layout, Function arrayFactory) { MemoryLayout seq = MemoryLayout.sequenceLayout((Integer.MAX_VALUE * layout.byteSize()) + 1, layout); //do not really allocate here, as it's way too much memory MemorySegment segment = MemorySegment.NULL.reinterpret(seq.byteSize()); - arrayFactory.apply(segment); + assertThrows(IllegalStateException.class, () -> { + arrayFactory.apply(segment); + }); } - @Test(dataProvider = "elemLayouts", - expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("elemLayouts") public void testBadSize(MemoryLayout layout, Function arrayFactory) { - if (layout.byteSize() == 1) throw new IllegalStateException(); //make it fail + if (layout.byteSize() == 1) return; // skip try (Arena arena = Arena.ofConfined()) { long byteSize = layout.byteSize() + 1; long byteAlignment = layout.byteSize(); MemorySegment segment = arena.allocate(byteSize, byteAlignment); - arrayFactory.apply(segment); + assertThrows(IllegalStateException.class, () -> { + arrayFactory.apply(segment); + }); } } - @Test(dataProvider = "elemLayouts", - expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("elemLayouts") public void testArrayFromClosedSegment(MemoryLayout layout, Function arrayFactory) { Arena arena = Arena.ofConfined(); MemorySegment segment = arena.allocate(layout); arena.close(); - arrayFactory.apply(segment); + assertThrows(IllegalStateException.class, () -> { + arrayFactory.apply(segment); + }); } - @DataProvider(name = "arrays") public Object[][] nativeAccessOps() { Consumer byteInitializer = (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, 0L, pos, (byte)(long)pos)); @@ -186,7 +196,6 @@ public Object[][] nativeAccessOps() { }; } - @DataProvider(name = "elemLayouts") public Object[][] elemLayouts() { return new Object[][] { { JAVA_BYTE, (Function)s -> s.toArray(JAVA_BYTE)}, diff --git a/test/jdk/java/foreign/TestByteBuffer.java b/test/jdk/java/foreign/TestByteBuffer.java index e45bb3fdbf0d..ab65a661ad98 100644 --- a/test/jdk/java/foreign/TestByteBuffer.java +++ b/test/jdk/java/foreign/TestByteBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @modules java.base/sun.nio.ch java.base/jdk.internal.foreign - * @run testng/othervm/timeout=600 --enable-native-access=ALL-UNNAMED TestByteBuffer + * @run junit/othervm/timeout=600 --enable-native-access=ALL-UNNAMED TestByteBuffer */ import java.lang.foreign.*; @@ -67,13 +67,19 @@ import java.util.function.Supplier; import java.util.stream.Stream; -import org.testng.SkipException; -import org.testng.annotations.*; import sun.nio.ch.DirectBuffer; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeFalse; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestByteBuffer { static final Path tempPath; @@ -125,9 +131,9 @@ static void checkTuples(MemorySegment base, ByteBuffer bb, long count) { for (long i = 0; i < count ; i++) { int index; float value; - assertEquals(index = bb.getInt(), (int)indexHandle.get(base, 0L, i)); - assertEquals(value = bb.getFloat(), (float)valueHandle.get(base, 0L, i)); - assertEquals(value, index / 500f); + assertEquals((int)indexHandle.get(base, 0L, i), index = bb.getInt()); + assertEquals((float)valueHandle.get(base, 0L, i), value = bb.getFloat()); + assertEquals(index / 500f, value); } } @@ -154,13 +160,13 @@ static void checkBytes(MemorySegment base, SequenceLayout lay Object bufferValue = bufferExtractor.apply(z); Object handleViewValue = handleExtractor.apply(segmentBufferView, j - i); if (handleValue instanceof Number) { - assertEquals(((Number)handleValue).longValue(), j); - assertEquals(((Number)bufferValue).longValue(), j); - assertEquals(((Number)handleViewValue).longValue(), j); + assertEquals(j, ((Number)handleValue).longValue()); + assertEquals(j, ((Number)bufferValue).longValue()); + assertEquals(j, ((Number)handleViewValue).longValue()); } else { - assertEquals((long)(char)handleValue, j); - assertEquals((long)(char)bufferValue, j); - assertEquals((long)(char)handleViewValue, j); + assertEquals(j, (long)(char)handleValue); + assertEquals(j, (long)(char)bufferValue); + assertEquals(j, (long)(char)handleViewValue); } } } @@ -248,19 +254,21 @@ public void testMappedSegment() throws Throwable { } } - @Test(dataProvider = "mappedOps", expectedExceptions = IllegalStateException.class) + @ParameterizedTest + @MethodSource("mappedOps") public void testMappedSegmentOperations(MappedSegmentOp mappedBufferOp) throws Throwable { File f = new File("test3.out"); f.createNewFile(); f.deleteOnExit(); - Arena arena = Arena.ofConfined(); try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) { MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 8L, arena); assertTrue(segment.isMapped()); assertTrue(segment.toString().contains("mapped")); arena.close(); - mappedBufferOp.apply(segment); + assertThrows(IllegalStateException.class, () -> { + mappedBufferOp.apply(segment); + }); } } @@ -294,7 +302,8 @@ public void testMappedSegmentOffset() throws Throwable { } } - @Test(dataProvider = "fromArrays") + @ParameterizedTest + @MethodSource("fromArrays") public void testAsByteBufferFromNonByteArray(MemorySegment segment) { if (!segment.heapBase().map(a -> a instanceof byte[]).get()) { // This should not work as the segment is not backed by a byte array @@ -318,12 +327,12 @@ public void testMappedSegmentAsByteBuffer() throws Throwable { segment.isLoaded(); segment.unload(); ByteBuffer byteBuffer = segment.asByteBuffer(); - assertEquals(byteBuffer.capacity(), segment.byteSize()); - assertEquals(byteBuffer.isReadOnly(), segment.isReadOnly()); + assertEquals(segment.byteSize(), byteBuffer.capacity()); + assertEquals(segment.isReadOnly(), byteBuffer.isReadOnly()); assertTrue(byteBuffer.isDirect()); } catch (IOException e) { - if (e.getMessage().equals("Function not implemented")) - throw new SkipException(e.getMessage(), e); + assumeFalse(e.getMessage().equals("Function not implemented"), + e.getMessage()); } finally { if (arena.scope() != Arena.global().scope()) { arena.close(); @@ -337,9 +346,7 @@ public void testMappedSegmentAsByteBuffer() throws Throwable { @Test public void testLargeMappedSegment() throws Throwable { - if (System.getProperty("sun.arch.data.model").equals("32")) { - throw new SkipException("large mapped files not supported on 32-bit systems"); - } + assumeFalse(System.getProperty("sun.arch.data.model").equals("32"), "large mapped files not supported on 32-bit systems"); File f = new File("testLargeMappedSegment.out"); f.createNewFile(); @@ -356,8 +363,8 @@ public void testLargeMappedSegment() throws Throwable { segment.unload(); segment.isLoaded(); } catch(IOException e) { - if (e.getMessage().equals("Function not implemented")) - throw new SkipException(e.getMessage(), e); + assumeFalse(e.getMessage().equals("Function not implemented"), + e.getMessage()); } } @@ -374,14 +381,13 @@ static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long } static void checkByteArrayAlignment(MemoryLayout layout) { - if (layout.byteSize() > 4 - && System.getProperty("sun.arch.data.model").equals("32")) { - throw new SkipException("avoid unaligned access on 32-bit system"); - } + assumeFalse(layout.byteSize() > 4 + && System.getProperty("sun.arch.data.model").equals("32"), "avoid unaligned access on 32-bit system"); } - @Test(dataProvider = "bufferOps") - public void testScopedBuffer(Function bufferFactory, @NoInjection Method method, Object[] args) { + @ParameterizedTest + @MethodSource("bufferOps") + public void testScopedBuffer(Function bufferFactory, Method method, Object[] args) { Buffer bb; try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(bytes); @@ -406,7 +412,8 @@ public void testScopedBuffer(Function bufferFactory, @NoInje } } - @Test(dataProvider = "bufferHandleOps") + @ParameterizedTest + @MethodSource("bufferHandleOps") public void testScopedBufferAndVarHandle(VarHandle bufferHandle) { ByteBuffer bb; try (Arena arena = Arena.ofConfined()) { @@ -441,20 +448,22 @@ public void testScopedBufferAndVarHandle(VarHandle bufferHandle) { } } - @Test(dataProvider = "bufferOps") - public void testDirectBuffer(Function bufferFactory, @NoInjection Method method, Object[] args) { + @ParameterizedTest + @MethodSource("bufferOps") + public void testDirectBuffer(Function bufferFactory, Method method, Object[] args) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(bytes); Buffer bb = bufferFactory.apply(segment.asByteBuffer()); assertTrue(bb.isDirect()); DirectBuffer directBuffer = ((DirectBuffer)bb); - assertEquals(directBuffer.address(), segment.address()); + assertEquals(segment.address(), directBuffer.address()); assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer)); assertTrue(directBuffer.cleaner() == null); } } - @Test(dataProvider="resizeOps") + @ParameterizedTest + @MethodSource("resizeOps") public void testResizeOffheap(Consumer checker, Consumer initializer, SequenceLayout seq) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(seq); @@ -463,7 +472,8 @@ public void testResizeOffheap(Consumer checker, Consumer checker, Consumer initializer, SequenceLayout seq) { checkByteArrayAlignment(seq.elementLayout()); int capacity = (int)seq.byteSize(); @@ -472,7 +482,8 @@ public void testResizeHeap(Consumer checker, Consumer checker, Consumer initializer, SequenceLayout seq) { checkByteArrayAlignment(seq.elementLayout()); int capacity = (int)seq.byteSize(); @@ -481,7 +492,8 @@ public void testResizeBuffer(Consumer checker, Consumer checker, Consumer initializer, SequenceLayout seq) { checkByteArrayAlignment(seq.elementLayout()); int capacity = (int)seq.byteSize(); @@ -492,7 +504,8 @@ public void testResizeRoundtripHeap(Consumer checker, Consumer checker, Consumer initializer, SequenceLayout seq) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(seq); @@ -502,39 +515,47 @@ public void testResizeRoundtripNative(Consumer checker, Consumer< } } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testBufferOnClosedSession() { MemorySegment leaked; try (Arena arena = Arena.ofConfined()) { leaked = arena.allocate(bytes); } ByteBuffer byteBuffer = leaked.asByteBuffer(); // ok - byteBuffer.get(); // should throw + assertThrows(IllegalStateException.class, () -> { + byteBuffer.get(); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testTooBigForByteBuffer() { MemorySegment segment = MemorySegment.NULL.reinterpret(Integer.MAX_VALUE + 10L); - segment.asByteBuffer(); + assertThrows(IllegalStateException.class, () -> { + segment.asByteBuffer(); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadMapNegativeSize() throws IOException { File f = new File("testNeg1.out"); f.createNewFile(); f.deleteOnExit(); try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) { - fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, -1L, Arena.ofAuto()); + assertThrows(IllegalArgumentException.class, () -> { + fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, -1L, Arena.ofAuto()); + }); } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadMapNegativeOffset() throws IOException { File f = new File("testNeg2.out"); f.createNewFile(); f.deleteOnExit(); try (FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) { - fileChannel.map(FileChannel.MapMode.READ_WRITE, -1L, 1L, Arena.ofAuto()); + assertThrows(IllegalArgumentException.class, () -> { + fileChannel.map(FileChannel.MapMode.READ_WRITE, -1L, 1L, Arena.ofAuto()); + }); } } @@ -559,7 +580,7 @@ public void testMapOffset() throws IOException { try (Arena arena = Arena.ofConfined(); FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) { MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, offset, SIZE - offset, arena); - assertEquals(segment.get(JAVA_BYTE, 0), offset); + assertEquals(offset, segment.get(JAVA_BYTE, 0)); } } } @@ -573,30 +594,30 @@ public void testMapZeroSize() throws IOException { try (Arena arena = Arena.ofConfined(); FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) { MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 0L, arena); - assertEquals(segment.byteSize(), 0); - assertEquals(segment.isMapped(), true); + assertEquals(0, segment.byteSize()); + assertEquals(true, segment.isMapped()); assertFalse(segment.isReadOnly()); segment.force(); segment.load(); segment.isLoaded(); segment.unload(); ByteBuffer byteBuffer = segment.asByteBuffer(); - assertEquals(byteBuffer.capacity(), 0); + assertEquals(0, byteBuffer.capacity()); assertFalse(byteBuffer.isReadOnly()); } //RO try (Arena arena = Arena.ofConfined(); FileChannel fileChannel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) { MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, 0L, arena); - assertEquals(segment.byteSize(), 0); - assertEquals(segment.isMapped(), true); + assertEquals(0, segment.byteSize()); + assertEquals(true, segment.isMapped()); assertTrue(segment.isReadOnly()); segment.force(); segment.load(); segment.isLoaded(); segment.unload(); ByteBuffer byteBuffer = segment.asByteBuffer(); - assertEquals(byteBuffer.capacity(), 0); + assertEquals(0, byteBuffer.capacity()); assertTrue(byteBuffer.isReadOnly()); } } @@ -622,7 +643,8 @@ public void testMapCustomPath() throws IOException { } } - @Test(dataProvider="resizeOps") + @ParameterizedTest + @MethodSource("resizeOps") public void testCopyHeapToNative(Consumer checker, Consumer initializer, SequenceLayout seq) { checkByteArrayAlignment(seq.elementLayout()); int bytes = (int)seq.byteSize(); @@ -635,7 +657,8 @@ public void testCopyHeapToNative(Consumer checker, Consumer checker, Consumer initializer, SequenceLayout seq) { checkByteArrayAlignment(seq.elementLayout()); int bytes = (int)seq.byteSize(); @@ -685,28 +708,30 @@ public void testOfBufferScopeReachable() throws InterruptedException { } } - @Test(dataProvider="bufferSources") + @ParameterizedTest + @MethodSource("bufferSources") public void testBufferToSegment(ByteBuffer bb, Predicate segmentChecker) { MemorySegment segment = MemorySegment.ofBuffer(bb); - assertEquals(segment.isReadOnly(), bb.isReadOnly()); + assertEquals(bb.isReadOnly(), segment.isReadOnly()); assertTrue(segmentChecker.test(segment)); assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize()))); - assertEquals(bb.capacity(), segment.byteSize()); + assertEquals(segment.byteSize(), bb.capacity()); //another round trip segment = MemorySegment.ofBuffer(segment.asByteBuffer()); - assertEquals(segment.isReadOnly(), bb.isReadOnly()); + assertEquals(bb.isReadOnly(), segment.isReadOnly()); assertTrue(segmentChecker.test(segment)); assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize()))); - assertEquals(bb.capacity(), segment.byteSize()); + assertEquals(segment.byteSize(), bb.capacity()); } - @Test(dataProvider="bufferSources") + @ParameterizedTest + @MethodSource("bufferSources") public void bufferProperties(ByteBuffer bb, Predicate _unused) { MemorySegment segment = MemorySegment.ofBuffer(bb); ByteBuffer buffer = segment.asByteBuffer(); - assertEquals(buffer.position(), 0); - assertEquals(buffer.capacity(), segment.byteSize()); - assertEquals(buffer.limit(), segment.byteSize()); + assertEquals(0, buffer.position()); + assertEquals(segment.byteSize(), buffer.capacity()); + assertEquals(segment.byteSize(), buffer.limit()); } @Test @@ -715,27 +740,28 @@ public void testRoundTripAccess() { MemorySegment ms = arena.allocate(4, 1); MemorySegment msNoAccess = ms.asReadOnly(); MemorySegment msRoundTrip = MemorySegment.ofBuffer(msNoAccess.asByteBuffer()); - assertEquals(msRoundTrip.scope(), ms.scope()); - assertEquals(msNoAccess.isReadOnly(), msRoundTrip.isReadOnly()); + assertEquals(ms.scope(), msRoundTrip.scope()); + assertEquals(msRoundTrip.isReadOnly(), msNoAccess.isReadOnly()); } } - @Test(dataProvider = "bufferFactories") + @ParameterizedTest + @MethodSource("bufferFactories") public void testDerivedBufferScopes(Supplier bufferFactory) { MemorySegment segment = MemorySegment.ofBuffer(bufferFactory.get()); assertEquals(segment.scope(), segment.scope()); // one level - assertEquals(segment.asSlice(0).scope(), segment.scope()); - assertEquals(segment.asReadOnly().scope(), segment.scope()); + assertEquals(segment.scope(), segment.asSlice(0).scope()); + assertEquals(segment.scope(), segment.asReadOnly().scope()); // two levels - assertEquals(segment.asSlice(0).asReadOnly().scope(), segment.scope()); - assertEquals(segment.asReadOnly().asSlice(0).scope(), segment.scope()); + assertEquals(segment.scope(), segment.asSlice(0).asReadOnly().scope()); + assertEquals(segment.scope(), segment.asReadOnly().asSlice(0).scope()); // check fresh every time MemorySegment another = MemorySegment.ofBuffer(bufferFactory.get()); - assertNotEquals(segment.scope(), another.scope()); + assertNotEquals(another.scope(), segment.scope()); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testDeadAccessOnClosedBufferSegment() { Arena arena = Arena.ofConfined(); MemorySegment s1 = arena.allocate(JAVA_INT); @@ -743,11 +769,13 @@ public void testDeadAccessOnClosedBufferSegment() { // memory freed arena.close(); - - s2.set(JAVA_INT, 0, 10); // Dead access! + assertThrows(IllegalStateException.class, () -> { + s2.set(JAVA_INT, 0, 10); // Dead access! + }); } - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void closeableArenas(Supplier arenaSupplier) throws IOException { File tmp = File.createTempFile("tmp", "txt"); tmp.deleteOnExit(); @@ -758,17 +786,18 @@ public void closeableArenas(Supplier arenaSupplier) throws IOException { segment.set(JAVA_BYTE, i, (byte) i); } ByteBuffer bb = segment.asByteBuffer(); - assertEquals(channel.write(bb), 10); + assertEquals(10, channel.write(bb)); segment.fill((byte)0x00); - assertEquals(bb.clear(), ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); - assertEquals(channel.position(0).read(bb.clear()), 10); - assertEquals(bb.flip(), ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + assertEquals(ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), bb.clear()); + assertEquals(10, channel.position(0).read(bb.clear())); + assertEquals(ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), bb.flip()); } } static final Class ISE = IllegalStateException.class; - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testIOOnClosedSegmentBuffer(Supplier arenaSupplier) throws IOException { File tmp = File.createTempFile("tmp", "txt"); tmp.deleteOnExit(); @@ -797,13 +826,13 @@ public void buffersAndArraysFromSlices() { var slice = segment.asSlice(4, newSize); var bytes = slice.toArray(JAVA_BYTE); - assertEquals(newSize, bytes.length); + assertEquals(bytes.length, newSize); var buffer = slice.asByteBuffer(); // Fails for heap segments, but passes for native segments: assertEquals(0, buffer.position()); - assertEquals(newSize, buffer.limit()); - assertEquals(newSize, buffer.capacity()); + assertEquals(buffer.limit(), newSize); + assertEquals(buffer.capacity(), newSize); } } @@ -817,7 +846,6 @@ public void viewsFromSharedSegment() { } } - @DataProvider(name = "segments") public static Object[][] segments() throws Throwable { return new Object[][] { { (Supplier) () -> Arena.ofAuto().allocate(16, 1)}, @@ -826,7 +854,6 @@ public static Object[][] segments() throws Throwable { }; } - @DataProvider(name = "closeableArenas") public static Object[][] closeableArenas() { return new Object[][] { { (Supplier) Arena::ofConfined}, @@ -834,7 +861,6 @@ public static Object[][] closeableArenas() { }; } - @DataProvider(name = "bufferOps") public static Object[][] bufferOps() throws Throwable { List args = new ArrayList<>(); bufferOpsArgs(args, bb -> bb, ByteBuffer.class); @@ -861,7 +887,6 @@ static void bufferOpsArgs(List argsList, Function } } - @DataProvider(name = "bufferHandleOps") public static Object[][] bufferHandleOps() throws Throwable { return new Object[][]{ { MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) }, @@ -889,7 +914,6 @@ static Map varHandleMembers(ByteBuffer bb, VarHandle han return members; } - @DataProvider(name = "resizeOps") public Object[][] resizeOps() { Consumer byteInitializer = (base) -> initBytes(base, bytes, (addr, pos) -> addr.set(JAVA_BYTE, pos, (byte)(long)pos)); @@ -994,7 +1018,6 @@ static Object defaultValue(Class c) { } } - @DataProvider(name = "bufferSources") public static Object[][] bufferSources() { Predicate heapTest = segment -> !segment.isNative() && !segment.isMapped(); Predicate nativeTest = segment -> segment.isNative() && !segment.isMapped(); @@ -1038,14 +1061,12 @@ void apply(MemorySegment segment) { } } - @DataProvider(name = "mappedOps") public static Object[][] mappedOps() { return Stream.of(MappedSegmentOp.values()) .map(op -> new Object[] { op }) .toArray(Object[][]::new); } - @DataProvider(name = "bufferFactories") public static Object[][] bufferFactories() { List> l = List.of( () -> ByteBuffer.allocate(10), @@ -1066,7 +1087,6 @@ public static Object[][] bufferFactories() { return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); } - @DataProvider(name = "fromArrays") public static Object[][] fromArrays() { int len = 16; return Stream.of( diff --git a/test/jdk/java/foreign/TestClassLoaderFindNative.java b/test/jdk/java/foreign/TestClassLoaderFindNative.java index 9d04a7f83af1..a11b8ef2a670 100644 --- a/test/jdk/java/foreign/TestClassLoaderFindNative.java +++ b/test/jdk/java/foreign/TestClassLoaderFindNative.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,18 @@ /* * @test - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestClassLoaderFindNative + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestClassLoaderFindNative */ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; import java.nio.ByteOrder; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; // FYI this test is run on 64-bit platforms only for now, // since the windows 32-bit linker fails and there @@ -58,7 +59,7 @@ public void testInvalidSymbolLookup() { @Test public void testVariableSymbolLookup() { MemorySegment segment = SymbolLookup.loaderLookup().find("c").get().reinterpret(4); - assertEquals(segment.get(JAVA_INT, 0), 42); + assertEquals(42, segment.get(JAVA_INT, 0)); } @Test diff --git a/test/jdk/java/foreign/TestConcurrentClose.java b/test/jdk/java/foreign/TestConcurrentClose.java index 74f0ca2a8774..1d2b02ed8e04 100644 --- a/test/jdk/java/foreign/TestConcurrentClose.java +++ b/test/jdk/java/foreign/TestConcurrentClose.java @@ -31,7 +31,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run testng/othervm/timeout=480 + * @run junit/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI @@ -41,7 +41,6 @@ */ import jdk.test.whitebox.WhiteBox; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -53,7 +52,9 @@ import java.util.concurrent.atomic.AtomicLong; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.assertFalse; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import org.junit.jupiter.api.Test; public class TestConcurrentClose { static final WhiteBox WB = WhiteBox.getWhiteBox(); diff --git a/test/jdk/java/foreign/TestDereferencePath.java b/test/jdk/java/foreign/TestDereferencePath.java index e2281cde235e..c3706f0e79de 100644 --- a/test/jdk/java/foreign/TestDereferencePath.java +++ b/test/jdk/java/foreign/TestDereferencePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @run testng TestDereferencePath + * @run junit TestDereferencePath */ import java.lang.foreign.Arena; @@ -34,10 +34,11 @@ import java.lang.foreign.ValueLayout; -import org.testng.annotations.*; import java.lang.invoke.VarHandle; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestDereferencePath { @@ -73,7 +74,7 @@ public void testSingle() { c.set(ValueLayout.JAVA_INT, 0, 42); // dereference int val = (int) abcx.get(a, 0L); - assertEquals(val, 42); + assertEquals(42, val); } } @@ -109,13 +110,13 @@ public void testMulti() { c.setAtIndex(ValueLayout.JAVA_INT, 3, 4); // dereference int val00 = (int) abcx_multi.get(a, 0L, 0, 0); // a->b[0]->c[0] = 1 - assertEquals(val00, 1); + assertEquals(1, val00); int val10 = (int) abcx_multi.get(a, 0L, 1, 0); // a->b[1]->c[0] = 3 - assertEquals(val10, 3); + assertEquals(3, val10); int val01 = (int) abcx_multi.get(a, 0L, 0, 1); // a->b[0]->c[1] = 2 - assertEquals(val01, 2); + assertEquals(2, val01); int val11 = (int) abcx_multi.get(a, 0L, 1, 1); // a->b[1]->c[1] = 4 - assertEquals(val11, 4); + assertEquals(4, val11); } } @@ -138,44 +139,53 @@ public void testDerefValue() { b.set(ValueLayout.JAVA_INT, 0, 42); // dereference int val = (int) a_value.get(a, 0L); - assertEquals(val, 42); + assertEquals(42, val); } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testBadDerefInSelect() { - A.select(PathElement.groupElement("b"), PathElement.dereferenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + A.select(PathElement.groupElement("b"), PathElement.dereferenceElement()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testBadDerefInOffset() { - A.byteOffset(PathElement.groupElement("b"), PathElement.dereferenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + A.byteOffset(PathElement.groupElement("b"), PathElement.dereferenceElement()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void testBadDerefInSlice() { - A.sliceHandle(PathElement.groupElement("b"), PathElement.dereferenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + A.sliceHandle(PathElement.groupElement("b"), PathElement.dereferenceElement()); + }); } static final MemoryLayout A_MULTI_NO_TARGET = MemoryLayout.structLayout( ValueLayout.ADDRESS.withName("bs") ); - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void badDerefAddressNoTarget() { - A_MULTI_NO_TARGET.varHandle(PathElement.groupElement("bs"), PathElement.dereferenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + A_MULTI_NO_TARGET.varHandle(PathElement.groupElement("bs"), PathElement.dereferenceElement()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test void badDerefMisAligned() { MemoryLayout struct = MemoryLayout.structLayout( - ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT).withName("x")); - + ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT).withName("x")); try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(struct.byteSize() + 1, struct.byteAlignment()).asSlice(1); VarHandle vhX = struct.varHandle(PathElement.groupElement("x"), PathElement.dereferenceElement()); - vhX.set(segment, 0L, 42); // should throw + assertThrows(IllegalArgumentException.class, () -> { + vhX.set(segment, 0L, 42); + }); } } } diff --git a/test/jdk/java/foreign/TestDowncallBase.java b/test/jdk/java/foreign/TestDowncallBase.java index ace8867000f0..66a4bb902e86 100644 --- a/test/jdk/java/foreign/TestDowncallBase.java +++ b/test/jdk/java/foreign/TestDowncallBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,9 @@ import java.util.function.Consumer; import java.util.stream.Stream; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDowncallBase extends CallGeneratorHelper { Object doCall(MemorySegment symbol, SegmentAllocator allocator, FunctionDescriptor descriptor, Object[] args) throws Throwable { diff --git a/test/jdk/java/foreign/TestDowncallScope.java b/test/jdk/java/foreign/TestDowncallScope.java index 860fa74b533e..8b2bd75a89c1 100644 --- a/test/jdk/java/foreign/TestDowncallScope.java +++ b/test/jdk/java/foreign/TestDowncallScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,31 +26,35 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestDowncallScope * - * @run testng/othervm/native -Xint -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native -Xint -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=100000 * TestDowncallScope */ -import org.testng.annotations.Test; import java.lang.foreign.*; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDowncallScope extends TestDowncallBase { static { System.loadLibrary("TestDowncall"); } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testDowncall(int count, String fName, CallGeneratorHelper.Ret ret, List paramTypes, List fields) throws Throwable { @@ -68,7 +72,7 @@ public void testDowncall(int count, String fName, CallGeneratorHelper.Ret ret, checks.forEach(c -> c.accept(res)); if (needsScope) { // check that return struct has indeed been allocated in the native scope - assertEquals(((MemorySegment)res).scope(), arena.scope()); + assertEquals(arena.scope(), ((MemorySegment)res).scope()); } } } diff --git a/test/jdk/java/foreign/TestDowncallStack.java b/test/jdk/java/foreign/TestDowncallStack.java index 516a8a7e958c..193548405c72 100644 --- a/test/jdk/java/foreign/TestDowncallStack.java +++ b/test/jdk/java/foreign/TestDowncallStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,27 +26,31 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestDowncallStack */ -import org.testng.annotations.Test; import java.lang.foreign.*; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDowncallStack extends TestDowncallBase { static { System.loadLibrary("TestDowncallStack"); } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testDowncallStack(int count, String fName, CallGeneratorHelper.Ret ret, List paramTypes, List fields) throws Throwable { @@ -64,7 +68,7 @@ public void testDowncallStack(int count, String fName, CallGeneratorHelper.Ret r checks.forEach(c -> c.accept(res)); if (needsScope) { // check that return struct has indeed been allocated in the native scope - assertEquals(((MemorySegment)res).scope(), arena.scope()); + assertEquals(arena.scope(), ((MemorySegment)res).scope()); } } } diff --git a/test/jdk/java/foreign/TestFallbackLookup.java b/test/jdk/java/foreign/TestFallbackLookup.java index 5cc78bf747ca..939f72bf8a5d 100644 --- a/test/jdk/java/foreign/TestFallbackLookup.java +++ b/test/jdk/java/foreign/TestFallbackLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,15 @@ /* * @test - * @run testng/othervm -Dos.name=Windows --enable-native-access=ALL-UNNAMED TestFallbackLookup + * @run junit/othervm -Dos.name=Windows --enable-native-access=ALL-UNNAMED TestFallbackLookup */ -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import java.lang.foreign.Linker; +import org.junit.jupiter.api.Test; + public class TestFallbackLookup { @Test void testBadSystemLookupRequest() { diff --git a/test/jdk/java/foreign/TestFree.java b/test/jdk/java/foreign/TestFree.java index 31e9d9906e16..968eb6943d11 100644 --- a/test/jdk/java/foreign/TestFree.java +++ b/test/jdk/java/foreign/TestFree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ * @test * @bug 8248421 * @summary SystemCLinker should have a way to free memory allocated outside Java - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestFree + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestFree */ import java.lang.foreign.MemorySegment; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TestFree extends NativeTestHelper { public void test() throws Throwable { @@ -38,7 +38,7 @@ public void test() throws Throwable { MemorySegment addr = allocateMemory(str.length() + 1); addr.copyFrom(MemorySegment.ofArray(str.getBytes())); addr.set(C_CHAR, str.length(), (byte)0); - assertEquals(str, addr.getString(0)); + assertEquals(addr.getString(0), str); freeMemory(addr); } } diff --git a/test/jdk/java/foreign/TestFunctionDescriptor.java b/test/jdk/java/foreign/TestFunctionDescriptor.java index ef06f1048b20..858bc0f022c7 100644 --- a/test/jdk/java/foreign/TestFunctionDescriptor.java +++ b/test/jdk/java/foreign/TestFunctionDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestFunctionDescriptor + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestFunctionDescriptor */ import java.lang.foreign.FunctionDescriptor; @@ -32,9 +32,9 @@ import java.lang.invoke.MethodType; import java.util.List; import java.util.Optional; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestFunctionDescriptor extends NativeTestHelper { @@ -44,17 +44,17 @@ public class TestFunctionDescriptor extends NativeTestHelper { public void testOf() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); + assertEquals(List.of(C_DOUBLE, C_LONG_LONG), fd.argumentLayouts()); Optional returnLayoutOp = fd.returnLayout(); assertTrue(returnLayoutOp.isPresent()); - assertEquals(returnLayoutOp.get(), C_INT); + assertEquals(C_INT, returnLayoutOp.get()); } @Test public void testOfVoid() { FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_LONG_LONG); - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); + assertEquals(List.of(C_DOUBLE, C_LONG_LONG), fd.argumentLayouts()); Optional returnLayoutOp = fd.returnLayout(); assertFalse(returnLayoutOp.isPresent()); } @@ -64,10 +64,10 @@ public void testAppendArgumentLayouts() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); fd = fd.appendArgumentLayouts(C_POINTER); - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG, C_POINTER)); + assertEquals(List.of(C_DOUBLE, C_LONG_LONG, C_POINTER), fd.argumentLayouts()); Optional returnLayoutOp = fd.returnLayout(); assertTrue(returnLayoutOp.isPresent()); - assertEquals(returnLayoutOp.get(), C_INT); + assertEquals(C_INT, returnLayoutOp.get()); } @Test @@ -75,10 +75,10 @@ public void testChangeReturnLayout() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); fd = fd.changeReturnLayout(C_INT); - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); + assertEquals(List.of(C_DOUBLE, C_LONG_LONG), fd.argumentLayouts()); Optional returnLayoutOp = fd.returnLayout(); assertTrue(returnLayoutOp.isPresent()); - assertEquals(returnLayoutOp.get(), C_INT); + assertEquals(C_INT, returnLayoutOp.get()); } @Test @@ -86,7 +86,7 @@ public void testDropReturnLayout() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG); fd = fd.dropReturnLayout(); - assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG)); + assertEquals(List.of(C_DOUBLE, C_LONG_LONG), fd.argumentLayouts()); Optional returnLayoutOp = fd.returnLayout(); assertFalse(returnLayoutOp.isPresent()); } @@ -110,44 +110,58 @@ public void testCarrierMethodType() { MemoryLayout.structLayout(C_INT, C_INT), MemoryLayout.sequenceLayout(3, C_INT)); MethodType cmt = fd.toMethodType(); - assertEquals(cmt, MethodType.methodType(int.class, int.class, MemorySegment.class, MemorySegment.class)); + assertEquals(MethodType.methodType(int.class, int.class, MemorySegment.class, MemorySegment.class), cmt); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testIllegalInsertArgNegIndex() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT); - fd.insertArgumentLayouts(-1, C_INT); + assertThrows(IllegalArgumentException.class, () -> { + fd.insertArgumentLayouts(-1, C_INT); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testIllegalInsertArgOutOfBounds() { FunctionDescriptor fd = FunctionDescriptor.of(C_INT); - fd.insertArgumentLayouts(2, C_INT); + assertThrows(IllegalArgumentException.class, () -> { + fd.insertArgumentLayouts(2, C_INT); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPaddingInVoidFunction() { - FunctionDescriptor.ofVoid(MemoryLayout.paddingLayout(1)); + assertThrows(IllegalArgumentException.class, () -> { + FunctionDescriptor.ofVoid(MemoryLayout.paddingLayout(1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPaddingInNonVoidFunction() { - FunctionDescriptor.of(MemoryLayout.paddingLayout(1)); + assertThrows(IllegalArgumentException.class, () -> { + FunctionDescriptor.of(MemoryLayout.paddingLayout(1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPaddingInAppendArgLayouts() { - FunctionDescriptor.ofVoid().appendArgumentLayouts(MemoryLayout.paddingLayout(1)); + assertThrows(IllegalArgumentException.class, () -> { + FunctionDescriptor.ofVoid().appendArgumentLayouts(MemoryLayout.paddingLayout(1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPaddingInInsertArgLayouts() { - FunctionDescriptor.ofVoid().insertArgumentLayouts(0, MemoryLayout.paddingLayout(1)); + assertThrows(IllegalArgumentException.class, () -> { + FunctionDescriptor.ofVoid().insertArgumentLayouts(0, MemoryLayout.paddingLayout(1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadPaddingInChangeRetLayout() { - FunctionDescriptor.ofVoid().changeReturnLayout(MemoryLayout.paddingLayout(1)); + assertThrows(IllegalArgumentException.class, () -> { + FunctionDescriptor.ofVoid().changeReturnLayout(MemoryLayout.paddingLayout(1)); + }); } } diff --git a/test/jdk/java/foreign/TestHFA.java b/test/jdk/java/foreign/TestHFA.java index 40f2bf2f305c..927a2114c24a 100644 --- a/test/jdk/java/foreign/TestHFA.java +++ b/test/jdk/java/foreign/TestHFA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,17 +26,18 @@ * @test * @summary Test passing of Homogeneous Float Aggregates. * - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestHFA + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestHFA */ import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.*; +import org.junit.jupiter.api.Test; + public class TestHFA { static { @@ -108,7 +109,7 @@ public class TestHFA { fdpass_large_struct_after_structs); @Test - public static void testAddFloatStructs() { + public void testAddFloatStructs() { float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFFFFFFLayout); @@ -136,7 +137,7 @@ public static void testAddFloatStructs() { } @Test - public static void testAddFloatToStructAfterFloats() { + public void testAddFloatToStructAfterFloats() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -156,7 +157,7 @@ public static void testAddFloatToStructAfterFloats() { } @Test - public static void testAddFloatToStructAfterStructs() { + public void testAddFloatToStructAfterStructs() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -175,7 +176,7 @@ public static void testAddFloatToStructAfterStructs() { } @Test - public static void testAddDoubleToStructAfterStructs() { + public void testAddDoubleToStructAfterStructs() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -194,7 +195,7 @@ public static void testAddDoubleToStructAfterStructs() { } @Test - public static void testAddFloatToLargeStructAfterStructs() { + public void testAddFloatToLargeStructAfterStructs() { float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFFFFFFLayout); @@ -270,7 +271,7 @@ public static MemorySegment addDoubleToStructAfterStructs( } @Test - public static void testAddFloatStructsUpcall() { + public void testAddFloatStructsUpcall() { float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFFFFFFLayout); @@ -302,7 +303,7 @@ public static void testAddFloatStructsUpcall() { } @Test - public static void testAddFloatToStructAfterFloatsUpcall() { + public void testAddFloatToStructAfterFloatsUpcall() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -326,7 +327,7 @@ public static void testAddFloatToStructAfterFloatsUpcall() { } @Test - public static void testAddFloatToStructAfterStructsUpcall() { + public void testAddFloatToStructAfterStructsUpcall() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -349,7 +350,7 @@ public static void testAddFloatToStructAfterStructsUpcall() { } @Test - public static void testAddDoubleToStructAfterStructsUpcall() { + public void testAddDoubleToStructAfterStructsUpcall() { float p0 = 0.0f, p1 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFLayout); @@ -372,7 +373,7 @@ public static void testAddDoubleToStructAfterStructsUpcall() { } @Test - public static void testAddFloatToLargeStructAfterStructsUpcall() { + public void testAddFloatToLargeStructAfterStructsUpcall() { float p0 = 0.0f, p1 = 0.0f, p2 = 0.0f, p3 = 0.0f, p4 = 0.0f, p5 = 0.0f, p6 = 0.0f; try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(S_FFFFFFFLayout); diff --git a/test/jdk/java/foreign/TestHandshake.java b/test/jdk/java/foreign/TestHandshake.java index 86200b0e7d69..c2bbadc77efa 100644 --- a/test/jdk/java/foreign/TestHandshake.java +++ b/test/jdk/java/foreign/TestHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,10 @@ * @requires vm.flavor != "zero" * @modules java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc * @key randomness - * @run testng/othervm TestHandshake - * @run testng/othervm -Xint TestHandshake - * @run testng/othervm -XX:TieredStopAtLevel=1 TestHandshake - * @run testng/othervm -XX:-TieredCompilation TestHandshake + * @run junit/othervm TestHandshake + * @run junit/othervm -Xint TestHandshake + * @run junit/othervm -XX:TieredStopAtLevel=1 TestHandshake + * @run junit/othervm -XX:-TieredCompilation TestHandshake */ import java.lang.foreign.Arena; @@ -46,13 +46,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestHandshake { static final int ITERATIONS = 5; @@ -66,7 +69,8 @@ public class TestHandshake { static final AtomicLong start = new AtomicLong(); static final AtomicBoolean started = new AtomicBoolean(); - @Test(dataProvider = "accessors") + @ParameterizedTest + @MethodSource("accessors") public void testHandshake(String testName, AccessorFactory accessorFactory) throws InterruptedException { for (int it = 0 ; it < ITERATIONS ; it++) { Arena arena = Arena.ofShared(); @@ -286,7 +290,6 @@ interface AccessorFactory { AbstractSegmentAccessor make(int id, MemorySegment segment, Arena arena); } - @DataProvider static Object[][] accessors() { return new Object[][] { { "SegmentAccessor", (AccessorFactory)SegmentAccessor::new }, diff --git a/test/jdk/java/foreign/TestHeapAlignment.java b/test/jdk/java/foreign/TestHeapAlignment.java index cc8a95465108..328c0da6833f 100644 --- a/test/jdk/java/foreign/TestHeapAlignment.java +++ b/test/jdk/java/foreign/TestHeapAlignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestHeapAlignment + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestHeapAlignment */ import java.lang.foreign.AddressLayout; @@ -34,14 +34,17 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Function; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestHeapAlignment { - @Test(dataProvider = "layouts") + @ParameterizedTest + @MethodSource("layouts") public void testHeapAlignment(MemorySegment segment, int align, Object val, Object arr, ValueLayout layout, Function segmentFactory) { assertAligned(align, layout, () -> layout.varHandle().get(segment, 0L)); assertAligned(align, layout, () -> layout.varHandle().set(segment, 0L, val)); @@ -101,7 +104,6 @@ enum SegmentAndAlignment { } } - @DataProvider public static Object[][] layouts() { List layouts = new ArrayList<>(); for (SegmentAndAlignment testCase : SegmentAndAlignment.values()) { diff --git a/test/jdk/java/foreign/TestIllegalLink.java b/test/jdk/java/foreign/TestIllegalLink.java index 45239e3cb458..995efd199d63 100644 --- a/test/jdk/java/foreign/TestIllegalLink.java +++ b/test/jdk/java/foreign/TestIllegalLink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestIllegalLink + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestIllegalLink */ import java.lang.foreign.Arena; @@ -42,14 +42,18 @@ import java.util.List; import jdk.internal.foreign.CABI; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestIllegalLink extends NativeTestHelper { private static final boolean IS_SYSV = CABI.current() == CABI.SYS_V; @@ -59,7 +63,8 @@ public class TestIllegalLink extends NativeTestHelper { private static final MethodHandle DUMMY_TARGET_MH = MethodHandles.empty(MethodType.methodType(void.class)); private static final Linker ABI = Linker.nativeLinker(); - @Test(dataProvider = "types") + @ParameterizedTest + @MethodSource("types") public void testIllegalLayouts(FunctionDescriptor desc, Linker.Option[] options, String expectedExceptionMessage) { try { ABI.downcallHandle(DUMMY_TARGET, desc, options); @@ -70,34 +75,34 @@ public void testIllegalLayouts(FunctionDescriptor desc, Linker.Option[] options, } } - @Test(dataProvider = "downcallOnlyOptions", - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Not supported for upcall.*") + @ParameterizedTest + @MethodSource("downcallOnlyOptions") public void testIllegalUpcallOptions(Linker.Option downcallOnlyOption) { - ABI.upcallStub(DUMMY_TARGET_MH, FunctionDescriptor.ofVoid(), Arena.ofAuto(), downcallOnlyOption); + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> { + ABI.upcallStub(DUMMY_TARGET_MH, FunctionDescriptor.ofVoid(), Arena.ofAuto(), downcallOnlyOption); + }); + assertTrue(iae.getMessage().matches(".*Not supported for upcall.*")); } - @Test(dataProvider = "illegalCaptureState", - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Unknown name.*") + @ParameterizedTest + @MethodSource("illegalCaptureState") + @DisabledOnOs(OS.WINDOWS) public void testIllegalCaptureState(String name) { - Linker.Option.captureCallState(name); + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + Linker.Option.captureCallState(name); + }); + assertTrue(e.getMessage().matches(".*Unknown name.*")); } // where - @DataProvider public static Object[][] illegalCaptureState() { - if (!IS_WINDOWS) { - return new Object[][]{ - { "GetLastError" }, - { "WSAGetLastError" }, - }; - } - return new Object[][]{}; + return new Object[][]{ + { "GetLastError" }, + { "WSAGetLastError" }, + }; } - @DataProvider public static Object[][] downcallOnlyOptions() { return new Object[][]{ { Linker.Option.firstVariadicArg(0) }, @@ -106,7 +111,6 @@ public static Object[][] downcallOnlyOptions() { }; } - @DataProvider public static Object[][] types() { Linker.Option[] NO_OPTIONS = new Linker.Option[0]; List cases = new ArrayList<>(Arrays.asList(new Object[][]{ diff --git a/test/jdk/java/foreign/TestIntrinsics.java b/test/jdk/java/foreign/TestIntrinsics.java index 5024a9094971..5a940577f803 100644 --- a/test/jdk/java/foreign/TestIntrinsics.java +++ b/test/jdk/java/foreign/TestIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm/native + * @run junit/othervm/native * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * --enable-native-access=ALL-UNNAMED * -Xbatch @@ -39,13 +39,17 @@ import java.util.List; import java.lang.foreign.MemoryLayout; -import org.testng.annotations.*; import static java.lang.foreign.Linker.Option.firstVariadicArg; import static java.lang.invoke.MethodType.methodType; import static java.lang.foreign.ValueLayout.JAVA_CHAR; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestIntrinsics extends NativeTestHelper { static final Linker abi = Linker.nativeLinker(); @@ -57,14 +61,14 @@ private interface RunnableX { void run() throws Throwable; } - @Test(dataProvider = "tests") + @ParameterizedTest + @MethodSource("tests") public void testIntrinsics(RunnableX test) throws Throwable { for (int i = 0; i < 20_000; i++) { test.run(); } } - @DataProvider public Object[][] tests() { List testsList = new ArrayList<>(); @@ -74,7 +78,7 @@ interface AddTest { AddTest tests = (mh, expectedResult, args) -> testsList.add(() -> { Object actual = mh.invokeWithArguments(args); - assertEquals(actual, expectedResult); + assertEquals(expectedResult, actual); }); interface AddIdentity { diff --git a/test/jdk/java/foreign/TestLargeSegmentCopy.java b/test/jdk/java/foreign/TestLargeSegmentCopy.java index c1508e592c3d..8b7ad35f590e 100644 --- a/test/jdk/java/foreign/TestLargeSegmentCopy.java +++ b/test/jdk/java/foreign/TestLargeSegmentCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,16 +26,17 @@ * @test * @requires sun.arch.data.model == "64" * @bug 8292851 - * @run testng/othervm -Xmx4G TestLargeSegmentCopy + * @run junit/othervm -Xmx4G TestLargeSegmentCopy */ -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import static java.lang.foreign.ValueLayout.JAVA_LONG; +import org.junit.jupiter.api.Test; + public class TestLargeSegmentCopy { @Test diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java index 6729fbf82368..e4b5c116fc12 100644 --- a/test/jdk/java/foreign/TestLayoutPaths.java +++ b/test/jdk/java/foreign/TestLayoutPaths.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,12 @@ /* * @test - * @run testng TestLayoutPaths + * @run junit TestLayoutPaths */ import java.lang.foreign.*; import java.lang.foreign.MemoryLayout.PathElement; -import org.testng.annotations.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -46,84 +45,116 @@ import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestLayoutPaths { - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadByteSelectFromSeq() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(groupElement("foo")); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(groupElement("foo")); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadByteSelectFromStruct() { GroupLayout g = MemoryLayout.structLayout(JAVA_INT); - g.byteOffset(sequenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + g.byteOffset(sequenceElement()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadByteSelectFromValue() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(sequenceElement(), sequenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(sequenceElement(), sequenceElement()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testUnknownByteStructField() { GroupLayout g = MemoryLayout.structLayout(JAVA_INT); - g.byteOffset(groupElement("foo")); + assertThrows(IllegalArgumentException.class, () -> { + g.byteOffset(groupElement("foo")); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testTooBigGroupElementIndex() { GroupLayout g = MemoryLayout.structLayout(JAVA_INT); - g.byteOffset(groupElement(1)); + assertThrows(IllegalArgumentException.class, () -> { + g.byteOffset(groupElement(1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNegativeGroupElementIndex() { GroupLayout g = MemoryLayout.structLayout(JAVA_INT); - g.byteOffset(groupElement(-1)); + assertThrows(IllegalArgumentException.class, () -> { + g.byteOffset(groupElement(-1)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testByteOutOfBoundsSeqIndex() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(sequenceElement(6)); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(sequenceElement(6)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNegativeSeqIndex() { - sequenceElement(-2); + assertThrows(IllegalArgumentException.class, () -> { + sequenceElement(-2); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testByteNegativeSeqIndex() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(sequenceElement(-2)); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(sequenceElement(-2)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testOutOfBoundsSeqRange() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(sequenceElement(6, 2)); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(sequenceElement(6, 2)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNegativeSeqRange() { - sequenceElement(-2, 2); + assertThrows(IllegalArgumentException.class, () -> { + sequenceElement(-2, 2); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testByteNegativeSeqRange() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); - seq.byteOffset(sequenceElement(-2, 2)); + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffset(sequenceElement(-2, 2)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testIncompleteAccess() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); - seq.varHandle(sequenceElement()); + assertThrows(IllegalArgumentException.class, () -> { + seq.varHandle(sequenceElement()); + }); } @Test @@ -132,10 +163,12 @@ public void testByteOffsetHandleRange() { seq.byteOffsetHandle(sequenceElement(0, 1)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testByteOffsetHandleBadRange() { SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); - seq.byteOffsetHandle(sequenceElement(5, 1)); // invalid range (starting position is outside the sequence) + assertThrows(IllegalArgumentException.class, () -> { + seq.byteOffsetHandle(sequenceElement(5, 1)); // invalid range (starting position is outside the sequence) + }); } @Test @@ -143,23 +176,23 @@ public void testBadAlignmentOfRoot() { MemoryLayout struct = MemoryLayout.structLayout( JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("x")); - assertEquals(struct.byteAlignment(), 4); + assertEquals(4, struct.byteAlignment()); try (Arena arena = Arena.ofConfined()) { MemorySegment seg = arena.allocate(struct.byteSize() + 2, struct.byteAlignment()).asSlice(2); - assertEquals(seg.address() % JAVA_SHORT.byteAlignment(), 0); // should be aligned - assertNotEquals(seg.address() % struct.byteAlignment(), 0); // should not be aligned + assertEquals(0, seg.address() % JAVA_SHORT.byteAlignment()); // should be aligned + assertNotEquals(0, seg.address() % struct.byteAlignment()); // should not be aligned String expectedMessage = "Target offset 0 is incompatible with alignment constraint " + struct.byteAlignment() + " (of [i4s2(x)]) for segment MemorySegment"; VarHandle vhX = struct.varHandle(groupElement("x")); - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> { + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> { vhX.set(seg, 0L, (short) 42); }); assertTrue(iae.getMessage().startsWith(expectedMessage)); MethodHandle sliceX = struct.sliceHandle(groupElement("x")); - iae = expectThrows(IllegalArgumentException.class, () -> { + iae = assertThrows(IllegalArgumentException.class, () -> { MemorySegment slice = (MemorySegment) sliceX.invokeExact(seg, 0L); }); assertTrue(iae.getMessage().startsWith(expectedMessage)); @@ -175,9 +208,9 @@ public void testWrongTypeRoot() { var expectedMessage = "Bad layout path: attempting to select a sequence element from a non-sequence layout: [i4i4]"; - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> struct.select(PathElement.sequenceElement())); - assertEquals(iae.getMessage(), expectedMessage); + assertEquals(expectedMessage, iae.getMessage()); } @Test @@ -195,11 +228,11 @@ public void testWrongTypeEnclosing() { "[2:[i4(3a)i4(3b)](2)](1), selected from: " + "[[2:[i4(3a)i4(3b)](2)](1)](0)"; - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> struct.select(PathElement.groupElement("1"), PathElement.sequenceElement(), PathElement.sequenceElement())); - assertEquals(iae.getMessage(), expectedMessage); + assertEquals(expectedMessage, iae.getMessage()); } @Test @@ -229,7 +262,8 @@ public void testBadSequencePathInSelect() { } } - @Test(dataProvider = "groupSelectors") + @ParameterizedTest + @MethodSource("groupSelectors") public void testStructPaths(IntFunction groupSelector) { long[] offsets = { 0, 1, 3, 7 }; GroupLayout g = MemoryLayout.structLayout( @@ -250,11 +284,12 @@ public void testStructPaths(IntFunction groupSelector) { for (int i = 0 ; i < 4 ; i++) { long byteOffset = g.byteOffset(groupSelector.apply(i)); - assertEquals(offsets[i], byteOffset); + assertEquals(byteOffset, offsets[i]); } } - @Test(dataProvider = "groupSelectors") + @ParameterizedTest + @MethodSource("groupSelectors") public void testUnionPaths(IntFunction groupSelector) { long[] offsets = { 0, 0, 0, 0 }; GroupLayout g = MemoryLayout.unionLayout( @@ -275,11 +310,10 @@ public void testUnionPaths(IntFunction groupSelector) { for (int i = 0 ; i < 4 ; i++) { long byteOffset = g.byteOffset(groupSelector.apply(i)); - assertEquals(offsets[i], byteOffset); + assertEquals(byteOffset, offsets[i]); } } - @DataProvider public static Object[][] groupSelectors() { return new Object[][] { { (IntFunction) PathElement::groupElement }, // by index @@ -301,20 +335,22 @@ public void testSequencePaths() { for (int i = 0 ; i < 4 ; i++) { long byteOffset = g.byteOffset(sequenceElement(i)); - assertEquals(offsets[i], byteOffset); + assertEquals(byteOffset, offsets[i]); } } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements); byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); long actualByteOffset = (long) byteOffsetHandle.invokeExact(0L, indexes); - assertEquals(actualByteOffset, expectedByteOffset); + assertEquals(expectedByteOffset, actualByteOffset); } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { int[] badIndices = { -1, 10 }; @@ -332,15 +368,19 @@ public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElem } } - @Test(dataProvider = "testLayouts", expectedExceptions = ArithmeticException.class) + @ParameterizedTest + @MethodSource("testLayouts") public void testOffsetHandleOverflow(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements); - byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); - byteOffsetHandle.invoke(Long.MAX_VALUE, indexes); + MethodHandle finalHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); + assertThrows(ArithmeticException.class, () -> { + finalHandle.invoke(Long.MAX_VALUE, indexes); + }); } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); @@ -357,7 +397,8 @@ public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathEleme assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testSliceHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); @@ -373,7 +414,8 @@ public void testSliceHandleBadSegment(MemoryLayout layout, PathElement[] pathEle assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testArrayElementVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); @@ -395,46 +437,45 @@ public void testArrayElementVarHandleBadSegment(MemoryLayout layout, PathElement public void testHashCodeCollision() { PathElement sequenceElement = PathElement.sequenceElement(); PathElement dereferenceElement = PathElement.dereferenceElement(); - assertNotEquals(sequenceElement.hashCode(), dereferenceElement.hashCode()); + assertNotEquals(dereferenceElement.hashCode(), sequenceElement.hashCode()); } @Test public void testGroupElementIndexToString() { PathElement e = PathElement.groupElement(2); - assertEquals(e.toString(), "groupElement(2)"); + assertEquals("groupElement(2)", e.toString()); } @Test public void testGroupElementNameToString() { PathElement e = PathElement.groupElement("x"); - assertEquals(e.toString(), "groupElement(\"x\")"); + assertEquals("groupElement(\"x\")", e.toString()); } @Test public void testSequenceElementToString() { PathElement e = PathElement.sequenceElement(); - assertEquals(e.toString(), "sequenceElement()"); + assertEquals("sequenceElement()", e.toString()); } @Test public void testSequenceElementIndexToString() { PathElement e = PathElement.sequenceElement(2); - assertEquals(e.toString(), "sequenceElement(2)"); + assertEquals("sequenceElement(2)", e.toString()); } @Test public void testSequenceElementRangeToString() { PathElement e = PathElement.sequenceElement(2, 4); - assertEquals(e.toString(), "sequenceElement(2, 4)"); + assertEquals("sequenceElement(2, 4)", e.toString()); } @Test public void testDerefereceElementToString() { PathElement e = PathElement.dereferenceElement(); - assertEquals(e.toString(), "dereferenceElement()"); + assertEquals("dereferenceElement()", e.toString()); } - @DataProvider public static Object[][] testLayouts() { List testCases = new ArrayList<>(); @@ -510,7 +551,8 @@ public static Object[][] testLayouts() { return testCases.toArray(Object[][]::new); } - @Test(dataProvider = "testLayouts") + @ParameterizedTest + @MethodSource("testLayouts") public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { MemoryLayout selected = layout.select(pathElements); @@ -520,8 +562,8 @@ public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, lon try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(layout); MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, 0L, indexes); - assertEquals(slice.address() - segment.address(), expectedByteOffset); - assertEquals(slice.byteSize(), selected.byteSize()); + assertEquals(expectedByteOffset, slice.address() - segment.address()); + assertEquals(selected.byteSize(), slice.byteSize()); } } diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index 2606e0481b32..730d26fedc06 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestLayouts + * @run junit TestLayouts */ import java.lang.foreign.*; @@ -36,19 +36,28 @@ import java.util.function.LongFunction; import java.util.stream.Stream; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestLayouts { - @Test(dataProvider = "badAlignments", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("layoutsAndBadAlignments") public void testBadLayoutAlignment(MemoryLayout layout, long alignment) { - layout.withByteAlignment(alignment); + assertThrows(IllegalArgumentException.class, () -> { + layout.withByteAlignment(alignment); + }); } - @Test(dataProvider = "basicLayoutsAndAddressAndGroups") + @ParameterizedTest + @MethodSource("basicLayoutsAndAddressAndGroups") public void testEqualities(MemoryLayout layout) { // Use another Type @@ -110,26 +119,36 @@ public void testIndexedSequencePath() { } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadBoundSequenceLayoutResize() { SequenceLayout seq = MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT); - seq.withElementCount(-1); + assertThrows(IllegalArgumentException.class, () -> { + seq.withElementCount(-1); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testReshape() { SequenceLayout layout = MemoryLayout.sequenceLayout(10, JAVA_INT); - layout.reshape(); + assertThrows(IllegalArgumentException.class, () -> { + layout.reshape(); + }); } - @Test(dataProvider = "basicLayoutsAndAddressAndGroups", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("basicLayoutsAndAddressAndGroups") public void testGroupIllegalAlignmentNotPowerOfTwo(MemoryLayout layout) { - layout.withByteAlignment(9); + assertThrows(IllegalArgumentException.class, () -> { + layout.withByteAlignment(9); + }); } - @Test(dataProvider = "basicLayoutsAndAddressAndGroups", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("basicLayoutsAndAddressAndGroups") public void testGroupIllegalAlignmentNotGreaterOrEqualTo1(MemoryLayout layout) { - layout.withByteAlignment(0); + assertThrows(IllegalArgumentException.class, () -> { + layout.withByteAlignment(0); + }); } @Test @@ -137,18 +156,18 @@ public void testEqualsPadding() { PaddingLayout paddingLayout = MemoryLayout.paddingLayout(2); testEqualities(paddingLayout); PaddingLayout paddingLayout2 = MemoryLayout.paddingLayout(4); - assertNotEquals(paddingLayout, paddingLayout2); + assertNotEquals(paddingLayout2, paddingLayout); } @Test public void testEmptyGroup() { MemoryLayout struct = MemoryLayout.structLayout(); - assertEquals(struct.byteSize(), 0); - assertEquals(struct.byteAlignment(), 1); + assertEquals(0, struct.byteSize()); + assertEquals(1, struct.byteAlignment()); MemoryLayout union = MemoryLayout.unionLayout(); - assertEquals(union.byteSize(), 0); - assertEquals(union.byteAlignment(), 1); + assertEquals(0, union.byteSize()); + assertEquals(1, union.byteAlignment()); } @Test @@ -160,27 +179,30 @@ public void testStructSizeAndAlign() { ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG ); - assertEquals(struct.byteSize(), 1 + 1 + 2 + 4 + 8); - assertEquals(struct.byteAlignment(), 8); + assertEquals(1 + 1 + 2 + 4 + 8, struct.byteSize()); + assertEquals(8, struct.byteAlignment()); } - @Test(dataProvider="basicLayouts") + @ParameterizedTest + @MethodSource("basicLayouts") public void testPaddingNoAlign(MemoryLayout layout) { - assertEquals(MemoryLayout.paddingLayout(layout.byteSize()).byteAlignment(), 1); + assertEquals(1, MemoryLayout.paddingLayout(layout.byteSize()).byteAlignment()); } - @Test(dataProvider="basicLayouts") + @ParameterizedTest + @MethodSource("basicLayouts") public void testStructPaddingAndAlign(MemoryLayout layout) { MemoryLayout struct = MemoryLayout.structLayout( layout, MemoryLayout.paddingLayout(16 - layout.byteSize())); - assertEquals(struct.byteAlignment(), layout.byteAlignment()); + assertEquals(layout.byteAlignment(), struct.byteAlignment()); } - @Test(dataProvider="basicLayouts") + @ParameterizedTest + @MethodSource("basicLayouts") public void testUnionPaddingAndAlign(MemoryLayout layout) { MemoryLayout struct = MemoryLayout.unionLayout( layout, MemoryLayout.paddingLayout(16 - layout.byteSize())); - assertEquals(struct.byteAlignment(), layout.byteAlignment()); + assertEquals(layout.byteAlignment(), struct.byteAlignment()); } @Test @@ -191,8 +213,8 @@ public void testUnionSizeAndAlign() { ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG ); - assertEquals(struct.byteSize(), 8); - assertEquals(struct.byteAlignment(), 8); + assertEquals(8, struct.byteSize()); + assertEquals(8, struct.byteAlignment()); } @Test @@ -220,16 +242,16 @@ public void testSequenceOverflow() { @Test public void testSequenceLayoutWithZeroLength() { SequenceLayout layout = MemoryLayout.sequenceLayout(0, JAVA_INT); - assertEquals(layout.toString().toLowerCase(Locale.ROOT), "[0:i4]"); + assertEquals("[0:i4]", layout.toString().toLowerCase(Locale.ROOT)); SequenceLayout nested = MemoryLayout.sequenceLayout(0, layout); - assertEquals(nested.toString().toLowerCase(Locale.ROOT), "[0:[0:i4]]"); + assertEquals("[0:[0:i4]]", nested.toString().toLowerCase(Locale.ROOT)); SequenceLayout layout2 = MemoryLayout.sequenceLayout(0, JAVA_INT); - assertEquals(layout, layout2); + assertEquals(layout2, layout); SequenceLayout nested2 = MemoryLayout.sequenceLayout(0, layout2); - assertEquals(nested, nested2); + assertEquals(nested2, nested); } @Test @@ -246,14 +268,14 @@ public void testStructOverflow() { @Test public void testPadding() { var padding = MemoryLayout.paddingLayout(1); - assertEquals(padding.byteAlignment(), 1); + assertEquals(1, padding.byteAlignment()); } @Test public void testPaddingInStruct() { var padding = MemoryLayout.paddingLayout(1); var struct = MemoryLayout.structLayout(padding); - assertEquals(struct.byteAlignment(), 1); + assertEquals(1, struct.byteAlignment()); } @Test @@ -273,31 +295,34 @@ public void testStructToString() { for (ByteOrder order : List.of(ByteOrder.LITTLE_ENDIAN, ByteOrder.BIG_ENDIAN)) { String intRepresentation = (order == ByteOrder.LITTLE_ENDIAN ? "i" : "I"); StructLayout padding = MemoryLayout.structLayout(JAVA_INT.withOrder(order)).withName("struct"); - assertEquals(padding.toString(), "[" + intRepresentation + "4](struct)"); + assertEquals("[" + intRepresentation + "4](struct)", padding.toString()); var toStringUnaligned = padding.withByteAlignment(8).toString(); - assertEquals(toStringUnaligned, "8%[" + intRepresentation + "4](struct)"); + assertEquals("8%[" + intRepresentation + "4](struct)", toStringUnaligned); } } - @Test(dataProvider = "layoutKinds") + @ParameterizedTest + @MethodSource("layoutsKinds") public void testPadding(LayoutKind kind) { - assertEquals(kind == LayoutKind.PADDING, kind.layout instanceof PaddingLayout); + assertEquals(kind.layout instanceof PaddingLayout, kind == LayoutKind.PADDING); } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testAlignmentString(MemoryLayout layout, long byteAlign) { long[] alignments = { 1, 2, 4, 8, 16 }; for (long a : alignments) { if (layout.byteAlignment() == byteAlign) { assertFalse(layout.toString().contains("%")); if (a >= layout.byteAlignment()) { - assertEquals(layout.withByteAlignment(a).toString().contains("%"), a != byteAlign); + assertEquals(a != byteAlign, layout.withByteAlignment(a).toString().contains("%")); } } } } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadByteAlignment(MemoryLayout layout, long byteAlign) { long[] alignments = { 1, 2, 4, 8, 16 }; for (long a : alignments) { @@ -307,15 +332,17 @@ public void testBadByteAlignment(MemoryLayout layout, long byteAlign) { } } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadSequenceElementAlignmentTooBig(MemoryLayout layout, long byteAlign) { MemoryLayout elementLayout = layout.withByteAlignment(nextPowerOfTwo(layout.byteSize() * 2)); // hyper-align - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> MemoryLayout.sequenceLayout(1, elementLayout)); - assertEquals(iae.getMessage(), "Element layout size is not multiple of alignment"); + assertEquals("Element layout size is not multiple of alignment", iae.getMessage()); } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadSequenceElementSizeNotMultipleOfAlignment(MemoryLayout layout, long byteAlign) { boolean shouldFail = layout.byteSize() % layout.byteAlignment() != 0; try { @@ -326,7 +353,8 @@ public void testBadSequenceElementSizeNotMultipleOfAlignment(MemoryLayout layout } } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadSpliteratorElementSizeNotMultipleOfAlignment(MemoryLayout layout, long byteAlign) { boolean shouldFail = layout.byteSize() % layout.byteAlignment() != 0; try (Arena arena = Arena.ofConfined()) { @@ -338,7 +366,8 @@ public void testBadSpliteratorElementSizeNotMultipleOfAlignment(MemoryLayout lay } } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadElementsElementSizeNotMultipleOfAlignment(MemoryLayout layout, long byteAlign) { boolean shouldFail = layout.byteSize() % layout.byteAlignment() != 0; try (Arena arena = Arena.ofConfined()) { @@ -350,18 +379,21 @@ public void testBadElementsElementSizeNotMultipleOfAlignment(MemoryLayout layout } } - @Test(dataProvider="layoutsAndAlignments") + @ParameterizedTest + @MethodSource("layoutsAndAlignments") public void testBadStruct(MemoryLayout layout, long byteAlign) { MemoryLayout elementLayout = layout.withByteAlignment(nextPowerOfTwo(layout.byteSize() * 2)); // hyper-align - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> MemoryLayout.structLayout(elementLayout, elementLayout)); assertTrue(iae.getMessage().contains("Invalid alignment constraint for member layout")); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testSequenceElement() { - // Step must be != 0 - PathElement.sequenceElement(3, 0); + assertThrows(IllegalArgumentException.class, () -> { + // Step must be != 0 + PathElement.sequenceElement(3, 0); + }); } @Test @@ -373,29 +405,36 @@ public void testVarHandleCaching() { assertNotSame(ADDRESS.withTargetLayout(JAVA_INT).varHandle(), ADDRESS.varHandle()); } - @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*offset is negative.*") + @Test public void testScaleNegativeOffset() { - JAVA_INT.scale(-1, 0); + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + JAVA_INT.scale(-1, 0); + }); + assertTrue(e.getMessage().matches(".*offset is negative.*")); } - @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*index is negative.*") + @Test public void testScaleNegativeIndex() { - JAVA_INT.scale(0, -1); + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + JAVA_INT.scale(0, -1); + }); + assertTrue(e.getMessage().matches(".*index is negative.*")); } - @Test(expectedExceptions=ArithmeticException.class) + @Test public void testScaleAddOverflow() { - JAVA_INT.scale(Long.MAX_VALUE, 1); + assertThrows(ArithmeticException.class, () -> { + JAVA_INT.scale(Long.MAX_VALUE, 1); + }); } - @Test(expectedExceptions=ArithmeticException.class) + @Test public void testScaleMultiplyOverflow() { - JAVA_INT.scale(0, Long.MAX_VALUE); + assertThrows(ArithmeticException.class, () -> { + JAVA_INT.scale(0, Long.MAX_VALUE); + }); } - @DataProvider(name = "badAlignments") public Object[][] layoutsAndBadAlignments() { LayoutKind[] layoutKinds = LayoutKind.values(); Object[][] values = new Object[layoutKinds.length * 2][2]; @@ -406,7 +445,6 @@ public Object[][] layoutsAndBadAlignments() { return values; } - @DataProvider(name = "layoutKinds") public Object[][] layoutsKinds() { return Stream.of(LayoutKind.values()) .map(lk -> new Object[] { lk }) @@ -454,28 +492,24 @@ enum LayoutKind { } } - @DataProvider(name = "basicLayouts") public Object[][] basicLayouts() { return Stream.of(basicLayouts) .map(l -> new Object[] { l }) .toArray(Object[][]::new); } - @DataProvider(name = "basicLayoutsAndAddress") public Object[][] basicLayoutsAndAddress() { return Stream.concat(Stream.of(basicLayouts), Stream.of(ADDRESS)) .map(l -> new Object[] { l }) .toArray(Object[][]::new); } - @DataProvider(name = "basicLayoutsAndAddressAndGroups") public Object[][] basicLayoutsAndAddressAndGroups() { return Stream.concat(Stream.concat(Stream.of(basicLayouts), Stream.of(ADDRESS)), groupLayoutStream()) .map(l -> new Object[] { l }) .toArray(Object[][]::new); } - @DataProvider(name = "layoutsAndAlignments") public Object[][] layoutsAndAlignments() { List layoutsAndAlignments = new ArrayList<>(); int i = 0; @@ -505,14 +539,12 @@ public Object[][] layoutsAndAlignments() { return layoutsAndAlignments.toArray(Object[][]::new); } - @DataProvider(name = "groupLayouts") public Object[][] groupLayouts() { return groupLayoutStream() .map(l -> new Object[] { l }) .toArray(Object[][]::new); } - @DataProvider(name = "validCarriers") public Object[][] validCarriers() { return Stream.of( boolean.class, diff --git a/test/jdk/java/foreign/TestLinker.java b/test/jdk/java/foreign/TestLinker.java index 902b938ac62a..734361496724 100644 --- a/test/jdk/java/foreign/TestLinker.java +++ b/test/jdk/java/foreign/TestLinker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,14 +24,12 @@ /* * @test * @modules java.base/jdk.internal.foreign java.base/jdk.internal.foreign.abi.fallback - * @run testng TestLinker - * @run testng/othervm TestLinker + * @run junit TestLinker + * @run junit/othervm TestLinker */ import jdk.internal.foreign.CABI; import jdk.internal.foreign.abi.fallback.FallbackLinker; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; @@ -47,15 +45,22 @@ import static java.lang.foreign.MemoryLayout.*; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestLinker extends NativeTestHelper { static final boolean IS_FALLBACK_LINKER = CABI.current() == CABI.FALLBACK; record LinkRequest(FunctionDescriptor descriptor, Linker.Option... options) {} - @Test(dataProvider = "notSameCases") + @ParameterizedTest + @MethodSource("notSameCases") public void testLinkerOptionsCache(LinkRequest l1, LinkRequest l2) { Linker linker = Linker.nativeLinker(); MethodHandle mh1 = linker.downcallHandle(l1.descriptor(), l1.options()); @@ -64,7 +69,6 @@ public void testLinkerOptionsCache(LinkRequest l1, LinkRequest l2) { assertNotSame(mh1, mh2); } - @DataProvider public static Object[][] notSameCases() { FunctionDescriptor fd_II_V = FunctionDescriptor.ofVoid(C_INT, C_INT); return new Object[][]{ @@ -74,7 +78,8 @@ public static Object[][] notSameCases() { }; } - @Test(dataProvider = "namedDescriptors") + @ParameterizedTest + @MethodSource("namedDescriptors") public void testNamedLinkerCache(FunctionDescriptor f1, FunctionDescriptor f2) { Linker linker = Linker.nativeLinker(); MethodHandle mh1 = linker.downcallHandle(f1); @@ -83,7 +88,6 @@ public void testNamedLinkerCache(FunctionDescriptor f1, FunctionDescriptor f2) { assertSame(mh1, mh2); } - @DataProvider public static Object[][] namedDescriptors() { List cases = new ArrayList<>(Arrays.asList(new Object[][]{ { FunctionDescriptor.ofVoid(C_INT), @@ -120,7 +124,6 @@ public static Object[][] namedDescriptors() { return cases.toArray(Object[][]::new); } - @DataProvider public static Object[][] invalidIndexCases() { return new Object[][]{ { -1, }, @@ -128,22 +131,27 @@ public static Object[][] invalidIndexCases() { }; } - @Test(dataProvider = "invalidIndexCases", - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*not in bounds for descriptor.*") + @ParameterizedTest + @MethodSource("invalidIndexCases") public void testInvalidOption(int invalidIndex) { Linker.Option option = Linker.Option.firstVariadicArg(invalidIndex); FunctionDescriptor desc = FunctionDescriptor.ofVoid(); - Linker.nativeLinker().downcallHandle(desc, option); // throws + IllegalArgumentException e =assertThrows(IllegalArgumentException.class, () -> { + Linker.nativeLinker().downcallHandle(desc, option); + }); + assertTrue(e.getMessage().matches(".*not in bounds for descriptor.*")); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Unknown name.*") + @Test public void testInvalidPreservedValueName() { - Linker.Option.captureCallState("foo"); // throws + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + Linker.Option.captureCallState("foo"); + }); + assertTrue(e.getMessage().matches(".*Unknown name.*")); } - @Test(dataProvider = "canonicalTypeNames") + @ParameterizedTest + @MethodSource("canonicalTypeNames") public void testCanonicalLayouts(String typeName) { MemoryLayout layout = LINKER.canonicalLayouts().get(typeName); assertNotNull(layout); @@ -157,7 +165,7 @@ public void embeddedPaddingLayout() { StructLayout struct = MemoryLayout.structLayout(sequence); FunctionDescriptor fd = FunctionDescriptor.of(struct, struct); Linker linker = Linker.nativeLinker(); - var x = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + var x = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); assertTrue(x.getMessage().contains("not supported because a sequence of a padding layout is not allowed")); } @@ -167,7 +175,7 @@ public void groupLayoutWithOnlyPadding() { StructLayout struct = MemoryLayout.structLayout(padding); FunctionDescriptor fd = FunctionDescriptor.of(struct, struct); Linker linker = Linker.nativeLinker(); - var x = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + var x = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); assertTrue(x.getMessage().contains("is non-empty and only has padding layouts")); } @@ -180,9 +188,8 @@ public void interwovenPadding() { var struct = MemoryLayout.structLayout(JAVA_BYTE, padding1, padding2, JAVA_INT); var fd = FunctionDescriptor.of(struct, struct, struct); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), - "The padding layout x2 was preceded by another padding layout x1 in " + struct); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals( "The padding layout x2 was preceded by another padding layout x1 in " + struct, e.getMessage()); } @Test @@ -198,9 +205,8 @@ public void stackedPadding() { var union = MemoryLayout.unionLayout(struct32, padding32); var struct = MemoryLayout.structLayout(JAVA_BYTE, padding1, padding2, padding4, padding8, padding16, union); var fd = FunctionDescriptor.of(struct, struct, struct); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), - "The padding layout x2 was preceded by another padding layout x1 in " + struct); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals( "The padding layout x2 was preceded by another padding layout x1 in " + struct, e.getMessage()); } @Test @@ -208,8 +214,8 @@ public void paddingUnionByteSize3() { Linker linker = Linker.nativeLinker(); var union = MemoryLayout.unionLayout(MemoryLayout.paddingLayout(3), ValueLayout.JAVA_INT); var fd = FunctionDescriptor.of(union, union, union); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), "Superfluous padding x3 in " + union); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals("Superfluous padding x3 in " + union, e.getMessage()); } @Test @@ -217,8 +223,8 @@ public void paddingUnionByteSize4() { Linker linker = Linker.nativeLinker(); var union = MemoryLayout.unionLayout(MemoryLayout.paddingLayout(4), ValueLayout.JAVA_INT); var fd = FunctionDescriptor.of(union, union, union); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), "Superfluous padding x4 in " + union); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals("Superfluous padding x4 in " + union, e.getMessage()); } @Test @@ -226,8 +232,8 @@ public void paddingUnionByteSize5() { Linker linker = Linker.nativeLinker(); var union = MemoryLayout.unionLayout(MemoryLayout.paddingLayout(5), ValueLayout.JAVA_INT); var fd = FunctionDescriptor.of(union, union, union); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), "Layout '" + union + "' has unexpected size: 5 != 4"); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals("Layout '" + union + "' has unexpected size: 5 != 4", e.getMessage()); } @Test @@ -239,8 +245,8 @@ public void paddingUnionSeveral() { MemoryLayout.paddingLayout(16), MemoryLayout.paddingLayout(16)); var fd = FunctionDescriptor.of(union, union, union); - var e = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); - assertEquals(e.getMessage(), "More than one padding in " + union); + var e = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + assertEquals("More than one padding in " + union, e.getMessage()); } @Test @@ -253,14 +259,13 @@ public void sequenceOfZeroElements() { var fd = FunctionDescriptor.of(struct8a8, struct8a8, struct8a8); if (linker.getClass().equals(FallbackLinker.class)) { // The fallback linker does not support empty layouts (FFI_BAD_TYPEDEF) - var iae = expectThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); + var iae = assertThrows(IllegalArgumentException.class, () -> linker.downcallHandle(fd)); assertTrue(iae.getMessage().contains("is empty")); } else { linker.downcallHandle(fd); } } - @DataProvider public static Object[][] canonicalTypeNames() { return new Object[][]{ { "bool" }, @@ -277,8 +282,10 @@ public static Object[][] canonicalTypeNames() { }; } - @Test(expectedExceptions=UnsupportedOperationException.class) + @Test public void testCanonicalLayoutsUnmodifiable() { - LINKER.canonicalLayouts().put("asdf", C_INT); + assertThrows(UnsupportedOperationException.class, () -> { + LINKER.canonicalLayouts().put("asdf", C_INT); + }); } } diff --git a/test/jdk/java/foreign/TestMappedHandshake.java b/test/jdk/java/foreign/TestMappedHandshake.java index 46fb4fb45fb9..262518d674bc 100644 --- a/test/jdk/java/foreign/TestMappedHandshake.java +++ b/test/jdk/java/foreign/TestMappedHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,10 +26,10 @@ * @requires vm.flavor != "zero" * @modules java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc * @key randomness - * @run testng/othervm TestMappedHandshake - * @run testng/othervm -Xint TestMappedHandshake - * @run testng/othervm -XX:TieredStopAtLevel=1 TestMappedHandshake - * @run testng/othervm -XX:-TieredCompilation TestMappedHandshake + * @run junit/othervm TestMappedHandshake + * @run junit/othervm -Xint TestMappedHandshake + * @run junit/othervm -XX:TieredStopAtLevel=1 TestMappedHandshake + * @run junit/othervm -XX:-TieredCompilation TestMappedHandshake */ import java.io.File; @@ -44,9 +44,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestMappedHandshake { diff --git a/test/jdk/java/foreign/TestMatrix.java b/test/jdk/java/foreign/TestMatrix.java index 4b2885da7ce0..befeddee6e47 100644 --- a/test/jdk/java/foreign/TestMatrix.java +++ b/test/jdk/java/foreign/TestMatrix.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallHighArity * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -46,7 +46,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallHighArity * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -57,7 +57,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallHighArity * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -68,7 +68,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallHighArity * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -79,7 +79,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * TestDowncallScope @@ -89,7 +89,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * TestDowncallScope @@ -99,7 +99,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * TestDowncallStack @@ -109,7 +109,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestDowncallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * TestDowncallStack @@ -119,7 +119,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -130,7 +130,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -141,7 +141,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -152,7 +152,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -163,7 +163,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -174,7 +174,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -185,7 +185,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -196,7 +196,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -207,7 +207,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -218,7 +218,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false @@ -229,7 +229,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -240,7 +240,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -252,7 +252,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper * - * @run testng/othervm/native/manual + * @run junit/othervm/native/manual * --enable-native-access=ALL-UNNAMED * TestVarArgs */ diff --git a/test/jdk/java/foreign/TestMemoryAccess.java b/test/jdk/java/foreign/TestMemoryAccess.java index ded9be1c085d..05f0ea3c5918 100644 --- a/test/jdk/java/foreign/TestMemoryAccess.java +++ b/test/jdk/java/foreign/TestMemoryAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,10 @@ /* * @test - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess */ import java.lang.foreign.*; @@ -36,42 +36,51 @@ import java.nio.ByteOrder; import java.util.function.Function; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMemoryAccess { - @Test(dataProvider = "elements") + @ParameterizedTest + @MethodSource("createData") public void testAccess(Function viewFactory, ValueLayout elemLayout, Checker checker) { ValueLayout layout = elemLayout.withName("elem"); testAccessInternal(viewFactory, layout, layout.varHandle(), checker); } - @Test(dataProvider = "elements") + @ParameterizedTest + @MethodSource("createData") public void testPaddedAccessByName(Function viewFactory, MemoryLayout elemLayout, Checker checker) { GroupLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.byteSize()), elemLayout.withName("elem")); testAccessInternal(viewFactory, layout, layout.varHandle(PathElement.groupElement("elem")), checker); } - @Test(dataProvider = "elements") + @ParameterizedTest + @MethodSource("createData") public void testPaddedAccessByIndexSeq(Function viewFactory, MemoryLayout elemLayout, Checker checker) { SequenceLayout layout = MemoryLayout.sequenceLayout(2, elemLayout); testAccessInternal(viewFactory, layout, layout.varHandle(PathElement.sequenceElement(1)), checker); } - @Test(dataProvider = "arrayElements") + @ParameterizedTest + @MethodSource("createArrayData") public void testArrayAccess(Function viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, elemLayout.withName("elem")); testArrayAccessInternal(viewFactory, seq, seq.varHandle(PathElement.sequenceElement()), checker); } - @Test(dataProvider = "arrayElements") + @ParameterizedTest + @MethodSource("createArrayData") public void testPaddedArrayAccessByName(Function viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.byteSize()), elemLayout.withName("elem"))); testArrayAccessInternal(viewFactory, seq, seq.varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("elem")), checker); } - @Test(dataProvider = "arrayElements") + @ParameterizedTest + @MethodSource("createArrayData") public void testPaddedArrayAccessByIndexSeq(Function viewFactory, MemoryLayout elemLayout, ArrayChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout)); testArrayAccessInternal(viewFactory, seq, seq.varHandle(PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1)), checker); @@ -143,7 +152,8 @@ private void testArrayAccessInternal(Function view } } - @Test(dataProvider = "matrixElements") + @ParameterizedTest + @MethodSource("createMatrixData") public void testMatrixAccess(Function viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, elemLayout.withName("elem"))); @@ -151,7 +161,8 @@ public void testMatrixAccess(Function viewFactory, PathElement.sequenceElement(), PathElement.sequenceElement()), checker); } - @Test(dataProvider = "matrixElements") + @ParameterizedTest + @MethodSource("createMatrixData") public void testPaddedMatrixAccessByName(Function viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.byteSize()), elemLayout.withName("elem")))); @@ -161,7 +172,8 @@ public void testPaddedMatrixAccessByName(Function checker); } - @Test(dataProvider = "matrixElements") + @ParameterizedTest + @MethodSource("createMatrixData") public void testPaddedMatrixAccessByIndexSeq(Function viewFactory, MemoryLayout elemLayout, MatrixChecker checker) { SequenceLayout seq = MemoryLayout.sequenceLayout(20, MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout))); @@ -211,7 +223,6 @@ private void testMatrixAccessInternal(Function vie static Function ID = Function.identity(); static Function IMMUTABLE = MemorySegment::asReadOnly; - @DataProvider(name = "elements") public Object[][] createData() { return new Object[][] { //BE, RW @@ -288,7 +299,6 @@ interface Checker { }; } - @DataProvider(name = "arrayElements") public Object[][] createArrayData() { return new Object[][] { //BE, RW @@ -331,41 +341,40 @@ interface ArrayChecker { ArrayChecker BYTE = (handle, segment, i) -> { handle.set(segment, 0L, i, (byte)i); - assertEquals(i, (byte)handle.get(segment, 0L, i)); + assertEquals((byte)handle.get(segment, 0L, i), i); }; ArrayChecker SHORT = (handle, segment, i) -> { handle.set(segment, 0L, i, (short)i); - assertEquals(i, (short)handle.get(segment, 0L, i)); + assertEquals((short)handle.get(segment, 0L, i), i); }; ArrayChecker CHAR = (handle, segment, i) -> { handle.set(segment, 0L, i, (char)i); - assertEquals(i, (char)handle.get(segment, 0L, i)); + assertEquals((char)handle.get(segment, 0L, i), i); }; ArrayChecker INT = (handle, segment, i) -> { handle.set(segment, 0L, i, (int)i); - assertEquals(i, (int)handle.get(segment, 0L, i)); + assertEquals((int)handle.get(segment, 0L, i), i); }; ArrayChecker LONG = (handle, segment, i) -> { handle.set(segment, 0L, i, (long)i); - assertEquals(i, (long)handle.get(segment, 0L, i)); + assertEquals((long)handle.get(segment, 0L, i), i); }; ArrayChecker FLOAT = (handle, segment, i) -> { handle.set(segment, 0L, i, (float)i); - assertEquals((float)i, (float)handle.get(segment, 0L, i)); + assertEquals((float)handle.get(segment, 0L, i), (float)i); }; ArrayChecker DOUBLE = (handle, segment, i) -> { handle.set(segment, 0L, i, (double)i); - assertEquals((double)i, (double)handle.get(segment, 0L, i)); + assertEquals((double)handle.get(segment, 0L, i), (double)i); }; } - @DataProvider(name = "matrixElements") public Object[][] createMatrixData() { return new Object[][] { //BE, RW @@ -416,47 +425,47 @@ interface MatrixChecker { MatrixChecker BYTE = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (byte)(r + c)); - assertEquals(r + c, (byte)handle.get(segment, 0L, r, c)); + assertEquals((byte)handle.get(segment, 0L, r, c), r + c); }; MatrixChecker BOOLEAN = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (r + c) != 0); - assertEquals((r + c) != 0, (boolean)handle.get(segment, 0L, r, c)); + assertEquals((boolean)handle.get(segment, 0L, r, c), (r + c) != 0); }; MatrixChecker SHORT = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (short)(r + c)); - assertEquals(r + c, (short)handle.get(segment, 0L, r, c)); + assertEquals((short)handle.get(segment, 0L, r, c), r + c); }; MatrixChecker CHAR = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (char)(r + c)); - assertEquals(r + c, (char)handle.get(segment, 0L, r, c)); + assertEquals((char)handle.get(segment, 0L, r, c), r + c); }; MatrixChecker INT = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (int)(r + c)); - assertEquals(r + c, (int)handle.get(segment, 0L, r, c)); + assertEquals((int)handle.get(segment, 0L, r, c), r + c); }; MatrixChecker LONG = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, r + c); - assertEquals(r + c, (long)handle.get(segment, 0L, r, c)); + assertEquals((long)handle.get(segment, 0L, r, c), r + c); }; MatrixChecker ADDR = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, MemorySegment.ofAddress(r + c)); - assertEquals(MemorySegment.ofAddress(r + c), (MemorySegment) handle.get(segment, 0L, r, c)); + assertEquals((MemorySegment) handle.get(segment, 0L, r, c), MemorySegment.ofAddress(r + c)); }; MatrixChecker FLOAT = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (float)(r + c)); - assertEquals((float)(r + c), (float)handle.get(segment, 0L, r, c)); + assertEquals((float)handle.get(segment, 0L, r, c), (float)(r + c)); }; MatrixChecker DOUBLE = (handle, segment, r, c) -> { handle.set(segment, 0L, r, c, (double)(r + c)); - assertEquals((double)(r + c), (double)handle.get(segment, 0L, r, c)); + assertEquals((double)handle.get(segment, 0L, r, c), (double)(r + c)); }; } } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index de1a17f5f113..617684f885d2 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_SEGMENT_FORCE_EXACT=true --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_SEGMENT_FORCE_EXACT=true --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance */ import java.lang.foreign.MemorySegment; @@ -33,10 +33,14 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; -import org.testng.annotations.*; -import org.testng.SkipException; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMemoryAccessInstance { static class Accessor { @@ -80,9 +84,9 @@ void test() { MemorySegment segment = arena.allocate(128, 1); ByteBuffer buffer = segment.asByteBuffer(); segmentSetter.set(segment, layout, 8, value); - assertEquals(bufferGetter.get(buffer, 8), value); + assertEquals(value, bufferGetter.get(buffer, 8)); bufferSetter.set(buffer, 8, value); - assertEquals(value, segmentGetter.get(segment, layout, 8)); + assertEquals(segmentGetter.get(segment, layout, 8), value); } } @@ -121,41 +125,45 @@ static Accessor of(L layout, X value, } } - @Test(dataProvider = "segmentAccessors") + @ParameterizedTest + @MethodSource("segmentAccessors") public void testSegmentAccess(String testName, Accessor accessor) { accessor.test(); } - @Test(dataProvider = "segmentAccessors") + @ParameterizedTest + @MethodSource("segmentAccessors") public void testSegmentAccessHyper(String testName, Accessor accessor) { - if (testName.contains("index")) { - accessor.testHyperAligned(); - } else { - throw new SkipException("Skipping"); - } + Assumptions.assumeTrue(testName.contains("index"), "Skipping"); + accessor.testHyperAligned(); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void badHeapSegmentSet() { long byteSize = ValueLayout.ADDRESS.byteSize(); Arena scope = Arena.ofAuto(); MemorySegment targetSegment = scope.allocate(byteSize, 1); MemorySegment segment = MemorySegment.ofArray(new byte[]{ 0, 1, 2 }); - targetSegment.set(ValueLayout.ADDRESS, 0, segment); // should throw + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + targetSegment.set(ValueLayout.ADDRESS, 0, segment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void badHeapSegmentSetAtIndex() { long byteSize = ValueLayout.ADDRESS.byteSize(); Arena scope = Arena.ofAuto(); MemorySegment targetSegment = scope.allocate(byteSize, 1); MemorySegment segment = MemorySegment.ofArray(new byte[]{ 0, 1, 2 }); - targetSegment.setAtIndex(ValueLayout.ADDRESS, 0, segment); // should throw + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + targetSegment.setAtIndex(ValueLayout.ADDRESS, 0, segment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } - @Test(dataProvider = "segmentAccessors") + @ParameterizedTest + @MethodSource("segmentAccessors") public void badAccessOverflowInIndexedAccess(String testName, Accessor accessor) { MemorySegment segment = MemorySegment.ofArray(new byte[100]); if (testName.contains("/index") && accessor.layout.byteSize() > 1) { @@ -164,7 +172,8 @@ public void badAccessOverflowInIndexedAccess(String t } } - @Test(dataProvider = "segmentAccessors") + @ParameterizedTest + @MethodSource("segmentAccessors") public void negativeOffset(String testName, Accessor accessor) { MemorySegment segment = MemorySegment.ofArray(new byte[100]); assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize())); @@ -173,7 +182,6 @@ public void negativeOffset(String testName, Accessor< static final ByteOrder NE = ByteOrder.nativeOrder(); - @DataProvider(name = "segmentAccessors") static Object[][] segmentAccessors() { return new Object[][]{ diff --git a/test/jdk/java/foreign/TestMemoryAlignment.java b/test/jdk/java/foreign/TestMemoryAlignment.java index 19f9f576ab2e..a80b7a98f150 100644 --- a/test/jdk/java/foreign/TestMemoryAlignment.java +++ b/test/jdk/java/foreign/TestMemoryAlignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestMemoryAlignment + * @run junit TestMemoryAlignment */ import java.io.File; @@ -46,18 +46,23 @@ import java.util.stream.LongStream; import java.util.stream.Stream; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMemoryAlignment { - @Test(dataProvider = "alignments") + @ParameterizedTest + @MethodSource("createAlignments") public void testAlignedAccess(long align) { ValueLayout layout = ValueLayout.JAVA_INT .withOrder(ByteOrder.BIG_ENDIAN); - assertEquals(layout.byteAlignment(), 4); + assertEquals(4, layout.byteAlignment()); ValueLayout aligned = layout.withByteAlignment(align); - assertEquals(aligned.byteAlignment(), align); //unreasonable alignment here, to make sure access throws + assertEquals(align, aligned.byteAlignment()); //unreasonable alignment here, to make sure access throws VarHandle vh = aligned.varHandle(); try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(aligned); @@ -69,24 +74,26 @@ public void testAlignedAccess(long align) { vh.set(nextSegment, 0L, 0xffffff); int val = (int)vh.get(segment, 0L); - assertEquals(val, -42); + assertEquals(-42, val); } } - @Test(dataProvider = "alignments") + @ParameterizedTest + @MethodSource("createAlignments") public void testUnalignedPath(long align) { MemoryLayout layout = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN); MemoryLayout aligned = layout.withByteAlignment(align).withName("value"); try { GroupLayout alignedGroup = MemoryLayout.structLayout(MemoryLayout.paddingLayout(1), aligned); alignedGroup.varHandle(PathElement.groupElement("value")); - assertEquals(align, 1); //this is the only case where path is aligned + assertEquals(1, align); //this is the only case where path is aligned } catch (IllegalArgumentException ex) { - assertNotEquals(align, 1); //if align != 8, path is always unaligned + assertNotEquals(1, align); //if align != 8, path is always unaligned } } - @Test(dataProvider = "alignments") + @ParameterizedTest + @MethodSource("createAlignments") public void testUnalignedSequence(long align) { try { SequenceLayout layout = MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withByteAlignment(align)); @@ -111,22 +118,23 @@ public void testPackedAccess() { GroupLayout g = MemoryLayout.structLayout(vChar.withByteAlignment(1).withName("a"), vShort.withByteAlignment(1).withName("b"), vInt.withByteAlignment(1).withName("c")); - assertEquals(g.byteAlignment(), 1); + assertEquals(1, g.byteAlignment()); VarHandle vh_c = g.varHandle(PathElement.groupElement("a")); VarHandle vh_s = g.varHandle(PathElement.groupElement("b")); VarHandle vh_i = g.varHandle(PathElement.groupElement("c")); try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(g);; vh_c.set(segment, 0L, Byte.MIN_VALUE); - assertEquals(vh_c.get(segment, 0L), Byte.MIN_VALUE); + assertEquals(Byte.MIN_VALUE, vh_c.get(segment, 0L)); vh_s.set(segment, 0L, Short.MIN_VALUE); - assertEquals(vh_s.get(segment, 0L), Short.MIN_VALUE); + assertEquals(Short.MIN_VALUE, vh_s.get(segment, 0L)); vh_i.set(segment, 0L, Integer.MIN_VALUE); - assertEquals(vh_i.get(segment, 0L), Integer.MIN_VALUE); + assertEquals(Integer.MIN_VALUE, vh_i.get(segment, 0L)); } } - @Test(dataProvider = "alignments") + @ParameterizedTest + @MethodSource("createAlignments") public void testActualByteAlignment(long align) { if (align > (1L << 10)) { return; @@ -135,8 +143,8 @@ public void testActualByteAlignment(long align) { var segment = arena.allocate(4, align); assertTrue(segment.maxByteAlignment() >= align); // Power of two? - assertEquals(Long.bitCount(segment.maxByteAlignment()), 1); - assertEquals(segment.asSlice(1).maxByteAlignment(), 1); + assertEquals(1, Long.bitCount(segment.maxByteAlignment())); + assertEquals(1, segment.asSlice(1).maxByteAlignment()); } } @@ -149,8 +157,8 @@ public void testActualByteAlignmentMappedSegment() throws IOException { // be positive. assertTrue(segment.maxByteAlignment() >= Byte.BYTES); // Power of two? - assertEquals(Long.bitCount(segment.maxByteAlignment()), 1); - assertEquals(segment.asSlice(1).maxByteAlignment(), 1); + assertEquals(1, Long.bitCount(segment.maxByteAlignment())); + assertEquals(1, segment.asSlice(1).maxByteAlignment()); } finally { tmp.delete(); } @@ -159,25 +167,24 @@ public void testActualByteAlignmentMappedSegment() throws IOException { @Test() public void testActualByteAlignmentNull() { long alignment = MemorySegment.NULL.maxByteAlignment(); - assertEquals(1L << 62, alignment); + assertEquals(alignment, 1L << 62); } - @Test(dataProvider = "heapSegments") + @ParameterizedTest + @MethodSource("heapSegments") public void testActualByteAlignmentHeap(MemorySegment segment, int bytes) { - assertEquals(segment.maxByteAlignment(), bytes); + assertEquals(bytes, segment.maxByteAlignment()); // A slice at offset 1 should always have an alignment of 1 var segmentSlice = segment.asSlice(1); - assertEquals(segmentSlice.maxByteAlignment(), 1); + assertEquals(1, segmentSlice.maxByteAlignment()); } - @DataProvider(name = "alignments") public Object[][] createAlignments() { return LongStream.range(1, 20) .mapToObj(v -> new Object[] { 1L << v }) .toArray(Object[][]::new); } - @DataProvider(name = "heapSegments") public Object[][] heapSegments() { return Stream.of( new Object[]{MemorySegment.ofArray(new byte[]{1}), Byte.BYTES}, diff --git a/test/jdk/java/foreign/TestMemoryDereference.java b/test/jdk/java/foreign/TestMemoryDereference.java index 4680b148b655..d8d373ba0399 100644 --- a/test/jdk/java/foreign/TestMemoryDereference.java +++ b/test/jdk/java/foreign/TestMemoryDereference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestMemoryDereference + * @run junit TestMemoryDereference */ import java.lang.foreign.MemorySegment; @@ -32,11 +32,15 @@ import java.nio.ByteOrder; import java.lang.foreign.ValueLayout; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMemoryDereference { static class Accessor { @@ -77,9 +81,9 @@ void test() { MemorySegment segment = MemorySegment.ofArray(new byte[32]); ByteBuffer buffer = segment.asByteBuffer(); segmentSetter.set(segment, value); - assertEquals(bufferGetter.get(buffer), value); + assertEquals(value, bufferGetter.get(buffer)); bufferSetter.set(buffer, value); - assertEquals(value, segmentGetter.get(segment)); + assertEquals(segmentGetter.get(segment), value); } Accessor of(Z value, @@ -89,7 +93,8 @@ Accessor of(Z value, } } - @Test(dataProvider = "accessors") + @ParameterizedTest + @MethodSource("accessors") public void testMemoryAccess(String testName, Accessor accessor) { accessor.test(); } @@ -98,7 +103,6 @@ public void testMemoryAccess(String testName, Accessor accessor) { static final ByteOrder LE = ByteOrder.LITTLE_ENDIAN; static final ByteOrder NE = ByteOrder.nativeOrder(); - @DataProvider(name = "accessors") static Object[][] accessors() { return new Object[][]{ diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java index b06e2707c399..03cd5b4c1298 100644 --- a/test/jdk/java/foreign/TestMemorySession.java +++ b/test/jdk/java/foreign/TestMemorySession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @run testng/othervm TestMemorySession + * @run junit/othervm TestMemorySession */ import java.lang.foreign.Arena; @@ -36,11 +36,14 @@ import java.util.function.Supplier; import java.util.stream.IntStream; import jdk.internal.foreign.MemorySessionImpl; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMemorySession { final static int N_THREADS = 100; @@ -53,13 +56,14 @@ public void testConfined() { int delta = i; addCloseAction(arena, () -> acc.addAndGet(delta)); } - assertEquals(acc.get(), 0); + assertEquals(0, acc.get()); arena.close(); - assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum()); + assertEquals(IntStream.range(0, N_THREADS).sum(), acc.get()); } - @Test(dataProvider = "sharedSessions") + @ParameterizedTest + @MethodSource("sharedSessions") public void testSharedSingleThread(ArenaSupplier arenaSupplier) { AtomicInteger acc = new AtomicInteger(); Arena session = arenaSupplier.get(); @@ -67,11 +71,11 @@ public void testSharedSingleThread(ArenaSupplier arenaSupplier) { int delta = i; addCloseAction(session, () -> acc.addAndGet(delta)); } - assertEquals(acc.get(), 0); + assertEquals(0, acc.get()); if (!TestMemorySession.ArenaSupplier.isImplicit(session)) { TestMemorySession.ArenaSupplier.close(session); - assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum()); + assertEquals(IntStream.range(0, N_THREADS).sum(), acc.get()); } else { session = null; int expected = IntStream.range(0, N_THREADS).sum(); @@ -81,7 +85,8 @@ public void testSharedSingleThread(ArenaSupplier arenaSupplier) { } } - @Test(dataProvider = "sharedSessions") + @ParameterizedTest + @MethodSource("sharedSessions") public void testSharedMultiThread(ArenaSupplier arenaSupplier) { AtomicInteger acc = new AtomicInteger(); List threads = new ArrayList<>(); @@ -101,7 +106,7 @@ public void testSharedMultiThread(ArenaSupplier arenaSupplier) { }); threads.add(thread); } - assertEquals(acc.get(), 0); + assertEquals(0, acc.get()); threads.forEach(Thread::start); // if no cleaner, close - not all segments might have been added to the session! @@ -126,7 +131,7 @@ public void testSharedMultiThread(ArenaSupplier arenaSupplier) { }); if (!TestMemorySession.ArenaSupplier.isImplicit(session)) { - assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum()); + assertEquals(IntStream.range(0, N_THREADS).sum(), acc.get()); } else { session = null; sessionRef.set(null); @@ -150,7 +155,7 @@ public void testLockSingleThread() { while (true) { try { arena.close(); - assertEquals(handles.size(), 0); + assertEquals(0, handles.size()); break; } catch (IllegalStateException ex) { assertTrue(handles.size() > 0); @@ -180,7 +185,7 @@ public void testLockSharedMultiThread() { while (true) { try { arena.close(); - assertEquals(lockCount.get(), 0); + assertEquals(0, lockCount.get()); break; } catch (IllegalStateException ex) { waitSomeTime(); @@ -215,13 +220,14 @@ public void testCloseConfinedLock() { try { t.join(); assertNotNull(failure.get()); - assertEquals(failure.get().getClass(), WrongThreadException.class); + assertEquals(WrongThreadException.class, failure.get().getClass()); } catch (Throwable ex) { throw new AssertionError(ex); } } - @Test(dataProvider = "allSessions") + @ParameterizedTest + @MethodSource("allSessions") public void testSessionAcquires(ArenaSupplier ArenaSupplier) { Arena session = ArenaSupplier.get(); acquireRecursive(session, 5); @@ -299,7 +305,8 @@ public void testConfinedSessionWithSharedDependency() { root.close(); } - @Test(dataProvider = "nonCloseableSessions") + @ParameterizedTest + @MethodSource("nonCloseableSessions") public void testNonCloseableSessions(ArenaSupplier arenaSupplier) { var arena = arenaSupplier.get(); var sessionImpl = ((MemorySessionImpl) arena.scope()); @@ -308,14 +315,15 @@ public void testNonCloseableSessions(ArenaSupplier arenaSupplier) { sessionImpl.close()); } - @Test(dataProvider = "allSessionsAndGlobal") + @ParameterizedTest + @MethodSource("allSessionsAndGlobal") public void testIsCloseableBy(ArenaSupplier arenaSupplier) { var arena = arenaSupplier.get(); var sessionImpl = ((MemorySessionImpl) arena.scope()); - assertEquals(sessionImpl.isCloseableBy(Thread.currentThread()), sessionImpl.isCloseable()); + assertEquals(sessionImpl.isCloseable(), sessionImpl.isCloseableBy(Thread.currentThread())); Thread otherThread = new Thread(); boolean isCloseableByOther = sessionImpl.isCloseable() && !"ConfinedSession".equals(sessionImpl.getClass().getSimpleName()); - assertEquals(sessionImpl.isCloseableBy(otherThread), isCloseableByOther); + assertEquals(isCloseableByOther, sessionImpl.isCloseableBy(otherThread)); } /** @@ -402,7 +410,6 @@ private void kickGC() { } } - @DataProvider static Object[][] drops() { return new Object[][] { { (Supplier) Arena::ofConfined}, @@ -444,7 +451,6 @@ static ArenaSupplier ofArena(Supplier arenaSupplier) { } } - @DataProvider(name = "sharedSessions") static Object[][] sharedSessions() { return new Object[][] { { ArenaSupplier.ofArena(Arena::ofShared) }, @@ -452,7 +458,6 @@ static Object[][] sharedSessions() { }; } - @DataProvider(name = "allSessions") static Object[][] allSessions() { return new Object[][] { { ArenaSupplier.ofArena(Arena::ofConfined) }, @@ -461,7 +466,6 @@ static Object[][] allSessions() { }; } - @DataProvider(name = "nonCloseableSessions") static Object[][] nonCloseableSessions() { return new Object[][] { { ArenaSupplier.ofGlobal() }, @@ -469,7 +473,6 @@ static Object[][] nonCloseableSessions() { }; } - @DataProvider(name = "allSessionsAndGlobal") static Object[][] allSessionsAndGlobal() { return new Object[][] { { ArenaSupplier.ofArena(Arena::ofConfined) }, diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index fa01f1553ebf..fc8854d74920 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8323552 - * @run testng/timeout=480 TestMismatch + * @run junit/timeout=480 TestMismatch */ import java.lang.foreign.Arena; @@ -39,12 +39,16 @@ import java.util.function.IntFunction; import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMismatch { // stores an increasing sequence of values into the memory of the given segment @@ -55,56 +59,76 @@ static MemorySegment initializeSegment(MemorySegment segment) { return segment; } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeSrcFromOffset(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, -1, 0, s2, 0, 0); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, -1, 0, s2, 0, 0); + }); } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeDstFromOffset(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, 0, 0, s2, -1, 0); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, 0, 0, s2, -1, 0); + }); } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeSrcToOffset(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, 0, -1, s2, 0, 0); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, 0, -1, s2, 0, 0); + }); } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeDstToOffset(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, 0, 0, s2, 0, -1); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, 0, 0, s2, 0, -1); + }); } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeSrcLength(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, 3, 2, s2, 0, 0); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, 3, 2, s2, 0, 0); + }); } - @Test(dataProvider = "slices", expectedExceptions = IndexOutOfBoundsException.class) + @ParameterizedTest + @MethodSource("slices") public void testNegativeDstLength(MemorySegment s1, MemorySegment s2) { - MemorySegment.mismatch(s1, 0, 0, s2, 3, 2); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.mismatch(s1, 0, 0, s2, 3, 2); + }); } - @Test(dataProvider = "slices") + @ParameterizedTest + @MethodSource("slices") public void testSameValues(MemorySegment ss1, MemorySegment ss2) { out.format("testSameValues s1:%s, s2:%s\n", ss1, ss2); MemorySegment s1 = initializeSegment(ss1); MemorySegment s2 = initializeSegment(ss2); if (s1.byteSize() == s2.byteSize()) { - assertEquals(s1.mismatch(s2), -1); // identical - assertEquals(s2.mismatch(s1), -1); + assertEquals(-1, s1.mismatch(s2)); // identical + assertEquals(-1, s2.mismatch(s1)); } else if (s1.byteSize() > s2.byteSize()) { - assertEquals(s1.mismatch(s2), s2.byteSize()); // proper prefix - assertEquals(s2.mismatch(s1), s2.byteSize()); + assertEquals(s2.byteSize(), s1.mismatch(s2)); // proper prefix + assertEquals(s2.byteSize(), s2.mismatch(s1)); } else { assert s1.byteSize() < s2.byteSize(); - assertEquals(s1.mismatch(s2), s1.byteSize()); // proper prefix - assertEquals(s2.mismatch(s1), s1.byteSize()); + assertEquals(s1.byteSize(), s1.mismatch(s2)); // proper prefix + assertEquals(s1.byteSize(), s2.mismatch(s1)); } } - @Test(dataProvider = "slicesStatic") + @ParameterizedTest + @MethodSource("slicesStatic") public void testSameValuesStatic(SliceOffsetAndSize ss1, SliceOffsetAndSize ss2) { out.format("testSameValuesStatic s1:%s, s2:%s\n", ss1, ss2); MemorySegment s1 = initializeSegment(ss1.toSlice()); @@ -114,13 +138,13 @@ public void testSameValuesStatic(SliceOffsetAndSize ss1, SliceOffsetAndSize ss2) long bytes = i - ss2.offset; long expected = (bytes == ss1.size) ? -1 : Long.min(ss1.size, bytes); - assertEquals(MemorySegment.mismatch(ss1.segment, ss1.offset, ss1.endOffset(), ss2.segment, ss2.offset, i), expected); + assertEquals(expected, MemorySegment.mismatch(ss1.segment, ss1.offset, ss1.endOffset(), ss2.segment, ss2.offset, i)); } for (long i = ss1.offset ; i < ss1.size ; i++) { long bytes = i - ss1.offset; long expected = (bytes == ss2.size) ? -1 : Long.min(ss2.size, bytes); - assertEquals(MemorySegment.mismatch(ss2.segment, ss2.offset, ss2.endOffset(), ss1.segment, ss1.offset, i), expected); + assertEquals(expected, MemorySegment.mismatch(ss2.segment, ss2.offset, ss2.endOffset(), ss1.segment, ss1.offset, i)); } } @@ -160,21 +184,21 @@ public void random() { } // They are not equal and differs in position beginDiff - assertEquals(src.mismatch(dst), beginDiff); - assertEquals(dst.mismatch(src), beginDiff); + assertEquals(beginDiff, src.mismatch(dst)); + assertEquals(beginDiff, dst.mismatch(src)); } else { // In this branch, there is no injection if (src.byteSize() == dst.byteSize()) { // The content matches and they are of equal size - assertEquals(src.mismatch(dst), -1); - assertEquals(dst.mismatch(src), -1); + assertEquals(-1, src.mismatch(dst)); + assertEquals(-1, dst.mismatch(src)); } else { // The content matches but they are of different length // Remember, the size of src is always smaller or equal // to the size of dst. - assertEquals(src.mismatch(dst), src.byteSize()); - assertEquals(dst.mismatch(src), src.byteSize()); + assertEquals(src.byteSize(), src.mismatch(dst)); + assertEquals(src.byteSize(), dst.mismatch(src)); } } } @@ -186,7 +210,8 @@ static byte randomByte(Random rnd) { return (byte) rnd.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE + 1); } - @Test(dataProvider = "slices") + @ParameterizedTest + @MethodSource("slices") public void testDifferentValues(MemorySegment s1, MemorySegment s2) { out.format("testDifferentValues s1:%s, s2:%s\n", s1, s2); s1 = initializeSegment(s1); @@ -197,21 +222,22 @@ public void testDifferentValues(MemorySegment s1, MemorySegment s2) { s2.set(ValueLayout.JAVA_BYTE, i, (byte) 0xFF); if (s1.byteSize() == s2.byteSize()) { - assertEquals(s1.mismatch(s2), expectedMismatchOffset); - assertEquals(s2.mismatch(s1), expectedMismatchOffset); + assertEquals(expectedMismatchOffset, s1.mismatch(s2)); + assertEquals(expectedMismatchOffset, s2.mismatch(s1)); } else if (s1.byteSize() > s2.byteSize()) { - assertEquals(s1.mismatch(s2), expectedMismatchOffset); - assertEquals(s2.mismatch(s1), expectedMismatchOffset); + assertEquals(expectedMismatchOffset, s1.mismatch(s2)); + assertEquals(expectedMismatchOffset, s2.mismatch(s1)); } else { assert s1.byteSize() < s2.byteSize(); var off = Math.min(s1.byteSize(), expectedMismatchOffset); - assertEquals(s1.mismatch(s2), off); // proper prefix - assertEquals(s2.mismatch(s1), off); + assertEquals(off, s1.mismatch(s2)); // proper prefix + assertEquals(off, s2.mismatch(s1)); } } } - @Test(dataProvider = "slicesStatic") + @ParameterizedTest + @MethodSource("slicesStatic") public void testDifferentValuesStatic(SliceOffsetAndSize ss1, SliceOffsetAndSize ss2) { out.format("testDifferentValues s1:%s, s2:%s\n", ss1, ss2); @@ -223,10 +249,10 @@ public void testDifferentValuesStatic(SliceOffsetAndSize ss1, SliceOffsetAndSize ss2.toSlice().set(ValueLayout.JAVA_BYTE, i, (byte) 0xFF); for (long j = expectedMismatchOffset + 1 ; j < ss2.size ; j++) { - assertEquals(MemorySegment.mismatch(ss1.segment, ss1.offset, ss1.endOffset(), ss2.segment, ss2.offset, j + ss2.offset), expectedMismatchOffset); + assertEquals(expectedMismatchOffset, MemorySegment.mismatch(ss1.segment, ss1.offset, ss1.endOffset(), ss2.segment, ss2.offset, j + ss2.offset)); } for (long j = expectedMismatchOffset + 1 ; j < ss1.size ; j++) { - assertEquals(MemorySegment.mismatch(ss2.segment, ss2.offset, ss2.endOffset(), ss1.segment, ss1.offset, j + ss1.offset), expectedMismatchOffset); + assertEquals(expectedMismatchOffset, MemorySegment.mismatch(ss2.segment, ss2.offset, ss2.endOffset(), ss1.segment, ss1.offset, j + ss1.offset)); } } } @@ -234,12 +260,12 @@ public void testDifferentValuesStatic(SliceOffsetAndSize ss1, SliceOffsetAndSize @Test public void testEmpty() { var s1 = MemorySegment.ofArray(new byte[0]); - assertEquals(s1.mismatch(s1), -1); + assertEquals(-1, s1.mismatch(s1)); try (Arena arena = Arena.ofConfined()) { var nativeSegment = arena.allocate(4, 4);; var s2 = nativeSegment.asSlice(0, 0); - assertEquals(s1.mismatch(s2), -1); - assertEquals(s2.mismatch(s1), -1); + assertEquals(-1, s1.mismatch(s2)); + assertEquals(-1, s2.mismatch(s1)); } } @@ -250,9 +276,9 @@ public void testLarge() { try (Arena arena = Arena.ofConfined()) { var s1 = arena.allocate((long) Integer.MAX_VALUE + 10L, 8);; var s2 = arena.allocate((long) Integer.MAX_VALUE + 10L, 8);; - assertEquals(s1.mismatch(s1), -1); - assertEquals(s1.mismatch(s2), -1); - assertEquals(s2.mismatch(s1), -1); + assertEquals(-1, s1.mismatch(s1)); + assertEquals(-1, s1.mismatch(s2)); + assertEquals(-1, s2.mismatch(s1)); testLargeAcrossMaxBoundary(s1, s2); @@ -266,13 +292,13 @@ private void testLargeAcrossMaxBoundary(MemorySegment s1, MemorySegment s2) { var s3 = s1.asSlice(0, i); var s4 = s2.asSlice(0, i); // instance - assertEquals(s3.mismatch(s3), -1); - assertEquals(s3.mismatch(s4), -1); - assertEquals(s4.mismatch(s3), -1); + assertEquals(-1, s3.mismatch(s3)); + assertEquals(-1, s3.mismatch(s4)); + assertEquals(-1, s4.mismatch(s3)); // static - assertEquals(MemorySegment.mismatch(s1, 0, s1.byteSize(), s1, 0, i), -1); - assertEquals(MemorySegment.mismatch(s2, 0, s1.byteSize(), s1, 0, i), -1); - assertEquals(MemorySegment.mismatch(s1, 0, s1.byteSize(), s2, 0, i), -1); + assertEquals(-1, MemorySegment.mismatch(s1, 0, s1.byteSize(), s1, 0, i)); + assertEquals(-1, MemorySegment.mismatch(s2, 0, s1.byteSize(), s1, 0, i)); + assertEquals(-1, MemorySegment.mismatch(s1, 0, s1.byteSize(), s2, 0, i)); } } @@ -280,8 +306,8 @@ private void testLargeMismatchAcrossMaxBoundary(MemorySegment s1, MemorySegment for (long i = s2.byteSize() -1 ; i >= Integer.MAX_VALUE - 10L; i--) { s2.set(ValueLayout.JAVA_BYTE, i, (byte) 0xFF); long expectedMismatchOffset = i; - assertEquals(s1.mismatch(s2), expectedMismatchOffset); - assertEquals(s2.mismatch(s1), expectedMismatchOffset); + assertEquals(expectedMismatchOffset, s1.mismatch(s2)); + assertEquals(expectedMismatchOffset, s2.mismatch(s1)); } } @@ -351,22 +377,22 @@ public void testSameSegment() { long match = MemorySegment.mismatch( segment, 0L, 4L, segment, 4L, 8L); - assertEquals(match, -1); + assertEquals(-1, match); long noMatch = MemorySegment.mismatch( segment, 0L, 4L, segment, 1L, 5L); - assertEquals(noMatch, 0); + assertEquals(0, noMatch); long noMatchEnd = MemorySegment.mismatch( segment, 0L, 2L, segment, 8L, 10L); - assertEquals(noMatchEnd, 1); + assertEquals(1, noMatchEnd); long same = MemorySegment.mismatch( segment, 0L, 8L, segment, 0L, 8L); - assertEquals(same, -1); + assertEquals(-1, same); } enum SegmentKind { @@ -393,7 +419,6 @@ long endOffset() { } }; - @DataProvider(name = "slicesStatic") static Object[][] slicesStatic() { int[] sizes = { 16, 8, 1 }; List aSliceOffsetAndSizes = new ArrayList<>(); @@ -419,7 +444,6 @@ static Object[][] slicesStatic() { return sliceArray; } - @DataProvider(name = "slices") static Object[][] slices() { Object[][] slicesStatic = slicesStatic(); return Stream.of(slicesStatic) diff --git a/test/jdk/java/foreign/TestNULLAddress.java b/test/jdk/java/foreign/TestNULLAddress.java index 32d19fb48740..a395f40117fa 100644 --- a/test/jdk/java/foreign/TestNULLAddress.java +++ b/test/jdk/java/foreign/TestNULLAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,11 @@ /* * @test - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * TestNULLAddress */ -import org.testng.annotations.Test; import java.lang.foreign.Linker; import java.lang.foreign.FunctionDescriptor; @@ -37,7 +36,8 @@ import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestNULLAddress { @@ -47,18 +47,22 @@ public class TestNULLAddress { static final Linker LINKER = Linker.nativeLinker(); - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNULLLinking() { - LINKER.downcallHandle( - MemorySegment.NULL, - FunctionDescriptor.ofVoid()); + assertThrows(IllegalArgumentException.class, () -> { + LINKER.downcallHandle( + MemorySegment.NULL, + FunctionDescriptor.ofVoid()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testNULLVirtual() throws Throwable { MethodHandle mh = LINKER.downcallHandle( FunctionDescriptor.ofVoid()); - mh.invokeExact(MemorySegment.NULL); + assertThrows(IllegalArgumentException.class, () -> { + mh.invokeExact(MemorySegment.NULL); + }); } @Test diff --git a/test/jdk/java/foreign/TestNative.java b/test/jdk/java/foreign/TestNative.java index c39a1292b400..a6fb348f65fe 100644 --- a/test/jdk/java/foreign/TestNative.java +++ b/test/jdk/java/foreign/TestNative.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,14 +24,12 @@ /* * @test - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestNative + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestNative */ import java.lang.foreign.*; import java.lang.foreign.MemoryLayout.PathElement; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.VarHandle; import java.nio.Buffer; @@ -49,8 +47,14 @@ import java.util.function.Function; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestNative extends NativeTestHelper { static SequenceLayout bytes = MemoryLayout.sequenceLayout(100, @@ -108,13 +112,13 @@ static void checkBytes(MemorySegment base, SequenceLayout lay Object bufferValue = nativeBufferExtractor.apply(z, (int)i); Object rawValue = nativeRawExtractor.apply(base.address(), (int)i); if (handleValue instanceof Number) { - assertEquals(((Number)handleValue).longValue(), i); - assertEquals(((Number)bufferValue).longValue(), i); - assertEquals(((Number)rawValue).longValue(), i); + assertEquals(i, ((Number)handleValue).longValue()); + assertEquals(i, ((Number)bufferValue).longValue()); + assertEquals(i, ((Number)rawValue).longValue()); } else { - assertEquals((long)(char)handleValue, i); - assertEquals((long)(char)bufferValue, i); - assertEquals((long)(char)rawValue, i); + assertEquals(i, (long)(char)handleValue); + assertEquals(i, (long)(char)bufferValue); + assertEquals(i, (long)(char)rawValue); } } } @@ -137,7 +141,8 @@ static void checkBytes(MemorySegment base, SequenceLayout lay public static native long getCapacity(Buffer buffer); - @Test(dataProvider="nativeAccessOps") + @ParameterizedTest + @MethodSource("nativeAccessOps") public void testNativeAccess(Consumer checker, Consumer initializer, SequenceLayout seq) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(seq);; @@ -146,7 +151,8 @@ public void testNativeAccess(Consumer checker, Consumer bufferFunction, int elemSize) { int capacity = (int)doubles.byteSize(); try (Arena arena = Arena.ofConfined()) { @@ -154,8 +160,8 @@ public void testNativeCapacity(Function bufferFunction, int ByteBuffer bb = segment.asByteBuffer(); Buffer buf = bufferFunction.apply(bb); int expected = capacity / elemSize; - assertEquals(buf.capacity(), expected); - assertEquals(getCapacity(buf), expected); + assertEquals(expected, buf.capacity()); + assertEquals(expected, getCapacity(buf)); } } @@ -176,7 +182,7 @@ public void testMallocSegment() { try (Arena arena = Arena.ofConfined()) { mallocSegment = addr.asSlice(0, 12) .reinterpret(arena, TestNative::freeMemory); - assertEquals(mallocSegment.byteSize(), 12); + assertEquals(12, mallocSegment.byteSize()); //free here } assertTrue(!mallocSegment.scope().isAlive()); @@ -186,7 +192,7 @@ public void testMallocSegment() { public void testAddressAccess() { MemorySegment addr = allocateMemory(4); addr.set(JAVA_INT, 0, 42); - assertEquals(addr.get(JAVA_INT, 0), 42); + assertEquals(42, addr.get(JAVA_INT, 0)); freeMemory(addr); } @@ -203,7 +209,6 @@ public void testBadResize() { System.loadLibrary("NativeAccess"); } - @DataProvider(name = "nativeAccessOps") public Object[][] nativeAccessOps() { Consumer byteInitializer = (base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, 0L, pos, (byte)(long)pos)); @@ -246,7 +251,6 @@ public Object[][] nativeAccessOps() { }; } - @DataProvider(name = "buffers") public Object[][] buffers() { return new Object[][] { { (Function)bb -> bb, 1 }, diff --git a/test/jdk/java/foreign/TestNulls.java b/test/jdk/java/foreign/TestNulls.java index 6822863c2ca1..8825809930af 100644 --- a/test/jdk/java/foreign/TestNulls.java +++ b/test/jdk/java/foreign/TestNulls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @modules java.base/jdk.internal.ref - * @run testng/othervm + * @run junit/othervm * --enable-native-access=ALL-UNNAMED * TestNulls */ @@ -32,9 +32,6 @@ import java.lang.foreign.*; import jdk.internal.ref.CleanerFactory; -import org.testng.annotations.DataProvider; -import org.testng.annotations.NoInjection; -import org.testng.annotations.Test; import java.lang.constant.Constable; import java.lang.foreign.Arena; @@ -62,8 +59,12 @@ import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static org.testng.Assert.*; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * This test makes sure that public API classes (listed in {@link TestNulls#CLASSES}) throws NPEs whenever @@ -75,6 +76,7 @@ * by adding/removing default mappings for standard carrier types (see {@link #DEFAULT_VALUES} or by * adding/removing custom replacements (see {@link #REPLACEMENT_VALUES}). */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestNulls { static final Class[] CLASSES = new Class[] { @@ -189,20 +191,20 @@ static void addReplacements(Class carrier, Z... value) { addReplacements(Set.class, null, Stream.of(new Object[] { null }).collect(Collectors.toSet())); } - @Test(dataProvider = "cases") - public void testNulls(String testName, @NoInjection Method meth, Object receiver, Object[] args) { + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("cases") + public void testNulls(String testName, Method meth, Object receiver, Object[] args) { try { meth.invoke(receiver, args); fail("Method invocation completed normally"); } catch (InvocationTargetException ex) { Class cause = ex.getCause().getClass(); - assertEquals(cause, NullPointerException.class, "got " + cause.getName() + " - expected NullPointerException"); + assertEquals(NullPointerException.class, cause, "got " + cause.getName() + " - expected NullPointerException"); } catch (Throwable ex) { fail("Unexpected exception: " + ex); } } - @DataProvider(name = "cases") static Iterator cases() { List cases = new ArrayList<>(); for (Class clazz : CLASSES) { diff --git a/test/jdk/java/foreign/TestOfBufferIssue.java b/test/jdk/java/foreign/TestOfBufferIssue.java index c30384efc692..e257d6586531 100644 --- a/test/jdk/java/foreign/TestOfBufferIssue.java +++ b/test/jdk/java/foreign/TestOfBufferIssue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,18 +22,18 @@ * */ -import org.testng.annotations.*; import java.lang.foreign.MemorySegment; import java.nio.CharBuffer; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /* * @test * @bug 8294621 * @summary test that StringCharBuffer is not accepted by MemorySegment::ofBuffer - * @run testng TestOfBufferIssue + * @run junit TestOfBufferIssue */ public class TestOfBufferIssue { diff --git a/test/jdk/java/foreign/TestReshape.java b/test/jdk/java/foreign/TestReshape.java index 5b64a3d38b67..2eedfd936abf 100644 --- a/test/jdk/java/foreign/TestReshape.java +++ b/test/jdk/java/foreign/TestReshape.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestReshape + * @run junit TestReshape */ import java.lang.foreign.MemoryLayout; @@ -34,12 +34,17 @@ import java.util.List; import java.util.stream.LongStream; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestReshape { - @Test(dataProvider = "shapes") + @ParameterizedTest + @MethodSource("shapes") public void testReshape(MemoryLayout layout, long[] expectedShape) { long flattenedSize = LongStream.of(expectedShape).reduce(1L, Math::multiplyExact); SequenceLayout seq_flattened = MemoryLayout.sequenceLayout(flattenedSize, layout); @@ -47,32 +52,40 @@ public void testReshape(MemoryLayout layout, long[] expectedShape) { for (long[] shape : new Shape(expectedShape)) { SequenceLayout seq_shaped = seq_flattened.reshape(shape); assertDimensions(seq_shaped, expectedShape); - assertEquals(seq_shaped.flatten(), seq_flattened); + assertEquals(seq_flattened, seq_shaped.flatten()); } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testInvalidReshape() { SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); - seq.reshape(3, 2); + assertThrows(IllegalArgumentException.class, () -> { + seq.reshape(3, 2); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadReshapeInference() { SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); - seq.reshape(-1, -1); + assertThrows(IllegalArgumentException.class, () -> { + seq.reshape(-1, -1); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadReshapeParameterZero() { SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); - seq.reshape(0, 4); + assertThrows(IllegalArgumentException.class, () -> { + seq.reshape(0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadReshapeParameterNegative() { SequenceLayout seq = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT); - seq.reshape(-2, 2); + assertThrows(IllegalArgumentException.class, () -> { + seq.reshape(-2, 2); + }); } static void assertDimensions(SequenceLayout layout, long... dims) { @@ -81,7 +94,7 @@ static void assertDimensions(SequenceLayout layout, long... dims) { if (prev != null) { layout = (SequenceLayout)prev.elementLayout(); } - assertEquals(layout.elementCount(), dims[i]); + assertEquals(dims[i], layout.elementCount()); prev = layout; } } @@ -110,7 +123,6 @@ public Iterator iterator() { ValueLayout.JAVA_INT ); - @DataProvider(name = "shapes") Object[][] shapes() { return new Object[][] { { ValueLayout.JAVA_BYTE, new long[] { 256 } }, diff --git a/test/jdk/java/foreign/TestRestricted.java b/test/jdk/java/foreign/TestRestricted.java index 771037ff8ba9..fc3012df7185 100644 --- a/test/jdk/java/foreign/TestRestricted.java +++ b/test/jdk/java/foreign/TestRestricted.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ * @test * @modules java.base/jdk.internal.javac * @modules java.base/jdk.internal.reflect - * @run testng TestRestricted + * @run junit TestRestricted */ import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; -import org.testng.annotations.Test; import java.io.IOException; import java.io.UncheckedIOException; @@ -57,8 +56,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; /** * This test checks all methods in java.base to make sure that methods annotated with {@link Restricted} are diff --git a/test/jdk/java/foreign/TestScope.java b/test/jdk/java/foreign/TestScope.java index cfc1f3deaff3..67458aad0d57 100644 --- a/test/jdk/java/foreign/TestScope.java +++ b/test/jdk/java/foreign/TestScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,9 @@ /* * @test - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestScope + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestScope */ -import org.testng.annotations.*; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -37,7 +36,8 @@ import java.util.HexFormat; import java.util.stream.LongStream; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestScope { @@ -49,21 +49,21 @@ public class TestScope { public void testDifferentArrayScope() { MemorySegment.Scope scope1 = MemorySegment.ofArray(new byte[10]).scope(); MemorySegment.Scope scope2 = MemorySegment.ofArray(new byte[10]).scope(); - assertNotEquals(scope1, scope2); + assertNotEquals(scope2, scope1); } @Test public void testDifferentBufferScope() { MemorySegment.Scope scope1 = MemorySegment.ofBuffer(ByteBuffer.allocateDirect(10)).scope(); MemorySegment.Scope scope2 = MemorySegment.ofBuffer(ByteBuffer.allocateDirect(10)).scope(); - assertNotEquals(scope1, scope2); + assertNotEquals(scope2, scope1); } @Test public void testDifferentArenaScope() { MemorySegment.Scope scope1 = Arena.ofAuto().allocate(10).scope(); MemorySegment.Scope scope2 = Arena.ofAuto().allocate(10).scope(); - assertNotEquals(scope1, scope2); + assertNotEquals(scope2, scope1); } @Test @@ -71,7 +71,7 @@ public void testSameArrayScope() { byte[] arr = new byte[10]; assertEquals(MemorySegment.ofArray(arr).scope(), MemorySegment.ofArray(arr).scope()); ByteBuffer buf = ByteBuffer.wrap(arr); - assertEquals(MemorySegment.ofArray(arr).scope(), MemorySegment.ofBuffer(buf).scope()); + assertEquals(MemorySegment.ofBuffer(buf).scope(), MemorySegment.ofArray(arr).scope()); testDerivedBufferScope(MemorySegment.ofArray(arr)); } @@ -87,7 +87,7 @@ public void testSameArenaScope() { try (Arena arena = Arena.ofConfined()) { MemorySegment segment1 = arena.allocate(10); MemorySegment segment2 = arena.allocate(10); - assertEquals(segment1.scope(), segment2.scope()); + assertEquals(segment2.scope(), segment1.scope()); testDerivedBufferScope(segment1); } } @@ -96,9 +96,9 @@ public void testSameArenaScope() { public void testSameNativeScope() { MemorySegment segment1 = MemorySegment.ofAddress(42); MemorySegment segment2 = MemorySegment.ofAddress(43); - assertEquals(segment1.scope(), segment2.scope()); - assertEquals(segment1.scope(), segment2.reinterpret(10).scope()); - assertEquals(segment1.scope(), Arena.global().scope()); + assertEquals(segment2.scope(), segment1.scope()); + assertEquals(segment2.reinterpret(10).scope(), segment1.scope()); + assertEquals(Arena.global().scope(), segment1.scope()); testDerivedBufferScope(segment1.reinterpret(10)); } @@ -107,7 +107,7 @@ public void testSameLookupScope() { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); MemorySegment segment1 = loaderLookup.find("f").get(); MemorySegment segment2 = loaderLookup.find("c").get(); - assertEquals(segment1.scope(), segment2.scope()); + assertEquals(segment2.scope(), segment1.scope()); testDerivedBufferScope(segment1.reinterpret(10)); } @@ -138,7 +138,7 @@ public void testZeroedOfShared() { void testDerivedBufferScope(MemorySegment segment) { ByteBuffer buffer = segment.asByteBuffer(); MemorySegment.Scope expectedScope = segment.scope(); - assertEquals(MemorySegment.ofBuffer(buffer).scope(), expectedScope); + assertEquals(expectedScope, MemorySegment.ofBuffer(buffer).scope()); // buffer slices should have same scope ByteBuffer slice = buffer.slice(0, 2); assertEquals(expectedScope, MemorySegment.ofBuffer(slice).scope()); @@ -153,7 +153,7 @@ void testZeroed(Arena arena) { long byteSize = ZEROED_MEMORY.byteSize(); var segment = arena.allocate(byteSize, Long.BYTES); long mismatch = ZEROED_MEMORY.mismatch(segment); - assertEquals(mismatch, -1); + assertEquals(-1, mismatch); } } diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 92b4ea5370fe..7cabbf75ee8c 100644 --- a/test/jdk/java/foreign/TestScopedOperations.java +++ b/test/jdk/java/foreign/TestScopedOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestScopedOperations + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestScopedOperations */ import java.lang.foreign.Arena; @@ -31,8 +31,6 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.File; import java.io.IOException; @@ -46,11 +44,16 @@ import java.util.function.Function; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestScopedOperations { static Path tempPath; @@ -65,7 +68,8 @@ public class TestScopedOperations { } } - @Test(dataProvider = "scopedOperations") + @ParameterizedTest + @MethodSource("scopedOperations") public void testOpAfterClose(String name, ScopedOperation scopedOperation) { Arena arena = Arena.ofConfined(); Z obj = scopedOperation.apply(arena); @@ -78,7 +82,8 @@ public void testOpAfterClose(String name, ScopedOperation scopedOperation } } - @Test(dataProvider = "scopedOperations") + @ParameterizedTest + @MethodSource("scopedOperations") public void testOpOutsideConfinement(String name, ScopedOperation scopedOperation) { try (Arena arena = Arena.ofConfined()) { Z obj = scopedOperation.apply(arena); @@ -93,7 +98,7 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedO t.start(); t.join(); assertNotNull(failed.get()); - assertEquals(failed.get().getClass(), WrongThreadException.class); + assertEquals(WrongThreadException.class, failed.get().getClass()); assertTrue(failed.get().getMessage().contains("outside")); } catch (InterruptedException ex) { throw new AssertionError(ex); @@ -140,7 +145,6 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedO ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg"); }; - @DataProvider(name = "scopedOperations") static Object[][] scopedOperations() { return scopedOperations.stream().map(op -> new Object[] { op.name, op }).toArray(Object[][]::new); } diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index c178f64450dd..63ecfce4d861 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @run testng/othervm TestSegmentAllocators + * @run junit/othervm TestSegmentAllocators */ import java.lang.foreign.*; -import org.testng.annotations.*; import java.lang.foreign.Arena; import java.lang.invoke.VarHandle; @@ -50,14 +49,20 @@ import java.util.function.BiFunction; import java.util.function.Function; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSegmentAllocators { final static int ELEMS = 128; - @Test(dataProvider = "scalarAllocations") @SuppressWarnings("unchecked") + @ParameterizedTest + @MethodSource("scalarAllocations") public void testAllocation(Z value, AllocationFactory allocationFactory, L layout, AllocationFunction allocationFunction, Function handleFactory) { layout = (L)layout.withByteAlignment(layout.byteSize()); L[] layouts = (L[])new ValueLayout[] { @@ -78,10 +83,10 @@ public void testAllocation(Z value, AllocationFactory SegmentAllocator allocator = allocationFactory.allocator(alignedLayout.byteSize() * ELEMS, arena); for (int i = 0; i < elems; i++) { MemorySegment address = allocationFunction.allocate(allocator, alignedLayout, value); - assertEquals(address.byteSize(), alignedLayout.byteSize()); + assertEquals(alignedLayout.byteSize(), address.byteSize()); addressList.add(address); VarHandle handle = handleFactory.apply(alignedLayout); - assertEquals(value, handle.get(address, 0L)); + assertEquals(handle.get(address, 0L), value); } boolean isBound = allocationFactory.isBound(); try { @@ -102,14 +107,18 @@ public void testAllocation(Z value, AllocationFactory static final int SIZE_256M = 1024 * 1024 * 256; - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testReadOnlySlicingAllocator() { - SegmentAllocator.slicingAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + assertThrows(IllegalArgumentException.class, () -> { + SegmentAllocator.slicingAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testReadOnlyPrefixAllocator() { - SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + assertThrows(IllegalArgumentException.class, () -> { + SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); + }); } @Test @@ -119,9 +128,9 @@ public void testBigAllocationInUnboundedSession() { SegmentAllocator allocator = SegmentAllocator.slicingAllocator(arena.allocate(i * 2 + 1)); MemorySegment address = allocator.allocate(i, i); //check size - assertEquals(address.byteSize(), i); + assertEquals(i, address.byteSize()); //check alignment - assertEquals(address.address() % i, 0); + assertEquals(0, address.address() % i); } } } @@ -135,59 +144,83 @@ public void testTooBigForBoundedArena() { } } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationSize(SegmentAllocator allocator) { - allocator.allocate(-1); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(-1); + }); } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationAlignZero(SegmentAllocator allocator) { - allocator.allocate(1, 0); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(1, 0); + }); } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationAlignNeg(SegmentAllocator allocator) { - allocator.allocate(1, -1); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(1, -1); + }); } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationAlignNotPowerTwo(SegmentAllocator allocator) { - allocator.allocate(1, 3); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(1, 3); + }); } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationArrayNegSize(SegmentAllocator allocator) { - allocator.allocate(ValueLayout.JAVA_BYTE, -1); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(ValueLayout.JAVA_BYTE, -1); + }); } - @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("allocators") public void testBadAllocationArrayOverflow(SegmentAllocator allocator) { - allocator.allocate(ValueLayout.JAVA_LONG, Long.MAX_VALUE); + assertThrows(IllegalArgumentException.class, () -> { + allocator.allocate(ValueLayout.JAVA_LONG, Long.MAX_VALUE); + }); } - @Test(expectedExceptions = OutOfMemoryError.class) + @Test public void testBadArenaNullReturn() { try (Arena arena = Arena.ofConfined()) { - arena.allocate(Long.MAX_VALUE, 2); + assertThrows(OutOfMemoryError.class, () -> { + arena.allocate(Long.MAX_VALUE, 2); + }); } } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void testArenaAllocateFromHeapSegment() { try (Arena arena = Arena.ofConfined()) { var heapSegment = MemorySegment.ofArray(new int[]{1}); - arena.allocateFrom(ValueLayout.ADDRESS, heapSegment); + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + arena.allocateFrom(ValueLayout.ADDRESS, heapSegment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void testAllocatorAllocateFromHeapSegment() { try (Arena arena = Arena.ofConfined()) { SegmentAllocator allocator = SegmentAllocator.prefixAllocator(arena.allocate(16)); var heapSegment = MemorySegment.ofArray(new int[]{1}); - allocator.allocateFrom(ValueLayout.ADDRESS, heapSegment); + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + allocator.allocateFrom(ValueLayout.ADDRESS, heapSegment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } } @@ -288,7 +321,7 @@ public MemorySegment allocateFrom(ValueLayout elementLayout, MemorySegment sourc allocator.allocateFrom(ValueLayout.JAVA_FLOAT); allocator.allocateFrom(ValueLayout.JAVA_LONG); allocator.allocateFrom(ValueLayout.JAVA_DOUBLE); - assertEquals(calls.get(), 7); + assertEquals(7, calls.get()); } @Test @@ -307,11 +340,12 @@ public MemorySegment allocate(long size) { }; }; allocator.allocateFrom("Hello"); - assertEquals(calls.get(), 1); + assertEquals(1, calls.get()); } - @Test(dataProvider = "arrayAllocations") + @ParameterizedTest + @MethodSource("arrayAllocations") public void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction allocationFunction, ToArrayHelper arrayHelper) { Z arr = arrayHelper.array(); Arena[] arenas = { @@ -323,12 +357,35 @@ public void testArray(AllocationFactory allocationFactory, ValueLayout layou SegmentAllocator allocator = allocationFactory.allocator(100, arena); MemorySegment address = allocationFunction.allocate(allocator, layout, arr); Z found = arrayHelper.toArray(address, layout); - assertEquals(found, arr); + assertArraysEqual(arr, found); } } } - @Test(dataProvider = "arrayAllocations") + private static void assertArraysEqual(Object arr, Object found) { + //in JUnit, assertEquals will really only call .equals, and that does not work well for arrays + //there's a set of explicit assertArrayEquals method, but we need "sharp" types for that to work(??): + if (arr instanceof byte[]) { + assertArrayEquals((byte[]) arr, (byte[]) found); + } else if (arr instanceof char[]) { + assertArrayEquals((char[]) arr, (char[]) found); + } else if (arr instanceof short[]) { + assertArrayEquals((short[]) arr, (short[]) found); + } else if (arr instanceof int[]) { + assertArrayEquals((int[]) arr, (int[]) found); + } else if (arr instanceof long[]) { + assertArrayEquals((long[]) arr, (long[]) found); + } else if (arr instanceof float[]) { + assertArrayEquals((float[]) arr, (float[]) found); + } else if (arr instanceof double[]) { + assertArrayEquals((double[]) arr, (double[]) found); + } else { + assertArrayEquals((Object[]) arr, (Object[]) found); + } + } + + @ParameterizedTest + @MethodSource("arrayAllocations") public void testPredicatesAndCommands(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction allocationFunction, ToArrayHelper arrayHelper) { Z arr = arrayHelper.array(); Arena[] arenas = { @@ -349,7 +406,6 @@ public void testPredicatesAndCommands(AllocationFactory allocationFactory, V } } - @DataProvider(name = "scalarAllocations") static Object[][] scalarAllocations() { List scalarAllocations = new ArrayList<>(); for (AllocationFactory factory : AllocationFactory.values()) { @@ -405,7 +461,6 @@ static Object[][] scalarAllocations() { return scalarAllocations.toArray(Object[][]::new); } - @DataProvider(name = "arrayAllocations") static Object[][] arrayAllocations() { List arrayAllocations = new ArrayList<>(); for (AllocationFactory factory : AllocationFactory.values()) { @@ -609,7 +664,6 @@ public double[] toArray(MemorySegment segment, ValueLayout layout) { }; } - @DataProvider(name = "allocators") static Object[][] allocators() { return new Object[][] { { SegmentAllocator.prefixAllocator(Arena.global().allocate(10, 1)) }, diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 9a4500b2f5a1..53e0d0d10dfd 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @run testng TestSegmentCopy + * @run junit TestSegmentCopy */ import java.lang.foreign.Arena; @@ -37,18 +37,23 @@ import java.util.List; import java.util.function.IntFunction; -import org.testng.SkipException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSegmentCopy { static final int TEST_BYTE_SIZE = 16; - @Test(dataProvider = "segmentKinds") + @ParameterizedTest + @MethodSource("segmentKinds") public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); @@ -75,7 +80,8 @@ public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { } } - @Test(dataProvider = "conjunctSegments") + @ParameterizedTest + @MethodSource("conjunctSegments") public void testCopy5ArgInvariants(MemorySegment src, MemorySegment dst) { assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 0, -1)); assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, -1, dst, 0, src.byteSize())); @@ -84,22 +90,26 @@ public void testCopy5ArgInvariants(MemorySegment src, MemorySegment dst) { assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 1, src.byteSize())); } - @Test(dataProvider = "conjunctSegments") + @ParameterizedTest + @MethodSource("conjunctSegments") public void testConjunctCopy7ArgRight(MemorySegment src, MemorySegment dst) { testConjunctCopy(src, 0, dst, 1, CopyOp.of7Arg()); } - @Test(dataProvider = "conjunctSegments") + @ParameterizedTest + @MethodSource("conjunctSegments") public void testConjunctCopy5ArgRight(MemorySegment src, MemorySegment dst) { testConjunctCopy(src, 0, dst, 1, CopyOp.of5Arg()); } - @Test(dataProvider = "conjunctSegments") + @ParameterizedTest + @MethodSource("conjunctSegments") public void testConjunctCopy7ArgLeft(MemorySegment src, MemorySegment dst) { testConjunctCopy(src, 1, dst, 0, CopyOp.of7Arg()); } - @Test(dataProvider = "conjunctSegments") + @ParameterizedTest + @MethodSource("conjunctSegments") public void testConjunctCopy5ArgLeft(MemorySegment src, MemorySegment dst) { testConjunctCopy(src, 1, dst, 0, CopyOp.of5Arg()); } @@ -121,7 +131,7 @@ void testConjunctCopy(MemorySegment src, long srcOffset, MemorySegment dst, long op.copy(src, srcOffset, dst, dstOffset, 3); byte[] actual = dst.toArray(JAVA_BYTE); - assertEquals(actual, expected); + assertArrayEquals(expected, actual); } } @@ -140,7 +150,8 @@ static CopyOp of7Arg() { } - @Test(dataProvider = "segmentKinds") + @ParameterizedTest + @MethodSource("segmentKinds") public void testByteCopySizes(SegmentKind kind1, SegmentKind kind2) { record Offsets(int src, int dst){} @@ -157,40 +168,46 @@ record Offsets(int src, int dst){} MemorySegment.copy(src, offsets.src(), dst, offsets.dst(), size); //check that copy actually worked for (int i = 0; i < size; i++) { - assertEquals(dst.get(JAVA_BYTE, i + offsets.dst()), (byte) i); + assertEquals((byte) i, dst.get(JAVA_BYTE, i + offsets.dst())); } } } } - @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "segmentKinds") + @ParameterizedTest + @MethodSource("segmentKinds") public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); // check failure with read-only dest - MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0); + }); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Attempt to write a read-only segment.*") + @Test public void badCopy6Arg() { try (Arena scope = Arena.ofConfined()) { MemorySegment dest = scope.allocate(ValueLayout.JAVA_INT).asReadOnly(); - MemorySegment.copy(new int[1],0, dest, ValueLayout.JAVA_INT, 0 ,1); // should throw + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(new int[1],0, dest, ValueLayout.JAVA_INT, 0 ,1); + }); + assertTrue(e.getMessage().matches(".*Attempt to write a read-only segment.*")); } } - @Test(expectedExceptions = IndexOutOfBoundsException.class, dataProvider = "types") + @ParameterizedTest + @MethodSource("types") public void testBadOverflow(Type type) { - if (type.layout.byteSize() > 1) { - MemorySegment segment = MemorySegment.ofArray(new byte[100]); + Assumptions.assumeTrue(type.layout.byteSize() > 1, "Byte layouts do not overflow"); + MemorySegment segment = MemorySegment.ofArray(new byte[100]); + assertThrows(IndexOutOfBoundsException.class, () -> { MemorySegment.copy(segment, type.layout, 0, segment, type.layout, 0, Long.MAX_VALUE); - } else { - throw new SkipException("Byte layouts do not overflow"); - } + }); } - @Test(dataProvider = "segmentKindsAndTypes") + @ParameterizedTest + @MethodSource("segmentKindsAndTypes") public void testElementCopy(SegmentKind kind1, SegmentKind kind2, Type type1, Type type2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); @@ -220,16 +237,20 @@ public void testElementCopy(SegmentKind kind1, SegmentKind kind2, Type type1, Ty } } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testHyperAlignedSrc() { MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); - MemorySegment.copy(segment, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(segment, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testHyperAlignedDst() { MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); - MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); + assertThrows(IllegalArgumentException.class, () -> { + MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); + }); } @Test @@ -334,7 +355,7 @@ void set(MemorySegment segment, long offset, int index, int val) { } void check(MemorySegment segment, long offset, int index, int val) { - assertEquals(handle().get(segment, offset + (index * size())), valueConverter.apply(val)); + assertEquals(valueConverter.apply(val), handle().get(segment, offset + (index * size()))); } } @@ -353,7 +374,6 @@ MemorySegment makeSegment(int size) { } } - @DataProvider static Object[][] segmentKinds() { List cases = new ArrayList<>(); for (SegmentKind kind1 : SegmentKind.values()) { @@ -364,7 +384,6 @@ static Object[][] segmentKinds() { return cases.toArray(Object[][]::new); } - @DataProvider static Object[][] conjunctSegments() { List cases = new ArrayList<>(); for (SegmentKind kind : SegmentKind.values()) { @@ -386,14 +405,12 @@ static Object[][] conjunctSegments() { return cases.toArray(Object[][]::new); } - @DataProvider static Object[][] types() { return Arrays.stream(Type.values()) .map(t -> new Object[] { t }) .toArray(Object[][]::new); } - @DataProvider static Object[][] segmentKindsAndTypes() { List cases = new ArrayList<>(); for (Object[] segmentKinds : segmentKinds()) { diff --git a/test/jdk/java/foreign/TestSegmentOverlap.java b/test/jdk/java/foreign/TestSegmentOverlap.java index 817d79b08ccf..bbade2fc4fff 100644 --- a/test/jdk/java/foreign/TestSegmentOverlap.java +++ b/test/jdk/java/foreign/TestSegmentOverlap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm TestSegmentOverlap + * @run junit/othervm TestSegmentOverlap */ import java.io.File; @@ -37,11 +37,14 @@ import java.util.function.Supplier; import java.lang.foreign.MemorySegment; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; import static java.lang.System.out; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSegmentOverlap { static Path tempPath; @@ -58,7 +61,6 @@ public class TestSegmentOverlap { } } - @DataProvider(name = "segmentFactories") public Object[][] segmentFactories() { List> l = List.of( () -> Arena.ofAuto().allocate(16, 1), @@ -80,7 +82,8 @@ public Object[][] segmentFactories() { return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); } - @Test(dataProvider="segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testBasic(Supplier segmentSupplier) { var s1 = segmentSupplier.get(); var s2 = segmentSupplier.get(); @@ -92,39 +95,41 @@ public void testBasic(Supplier segmentSupplier) { assertTrue(s1.asOverlappingSlice(sOther).isEmpty()); } - @Test(dataProvider="segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testIdentical(Supplier segmentSupplier) { var s1 = segmentSupplier.get(); var s2 = s1.asReadOnly(); out.format("testIdentical s1:%s, s2:%s\n", s1, s2); - assertEquals(s1.asOverlappingSlice(s2).get().byteSize(), s1.byteSize()); - assertEquals(s1.asOverlappingSlice(s2).get().scope(), s1.scope()); + assertEquals(s1.byteSize(), s1.asOverlappingSlice(s2).get().byteSize()); + assertEquals(s1.scope(), s1.asOverlappingSlice(s2).get().scope()); - assertEquals(s2.asOverlappingSlice(s1).get().byteSize(), s2.byteSize()); - assertEquals(s2.asOverlappingSlice(s1).get().scope(), s2.scope()); + assertEquals(s2.byteSize(), s2.asOverlappingSlice(s1).get().byteSize()); + assertEquals(s2.scope(), s2.asOverlappingSlice(s1).get().scope()); if (s1.isNative()) { - assertEquals(s1.asOverlappingSlice(s2).get().address(), s1.address()); - assertEquals(s2.asOverlappingSlice(s1).get().address(), s2.address()); + assertEquals(s1.address(), s1.asOverlappingSlice(s2).get().address()); + assertEquals(s2.address(), s2.asOverlappingSlice(s1).get().address()); } } - @Test(dataProvider="segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testSlices(Supplier segmentSupplier) { MemorySegment s1 = segmentSupplier.get(); MemorySegment s2 = segmentSupplier.get(); for (int offset = 0 ; offset < 4 ; offset++) { MemorySegment slice = s1.asSlice(offset); out.format("testSlices s1:%s, s2:%s, slice:%s, offset:%d\n", s1, s2, slice, offset); - assertEquals(s1.asOverlappingSlice(slice).get().byteSize(), s1.byteSize() - offset); - assertEquals(s1.asOverlappingSlice(slice).get().scope(), s1.scope()); + assertEquals(s1.byteSize() - offset, s1.asOverlappingSlice(slice).get().byteSize()); + assertEquals(s1.scope(), s1.asOverlappingSlice(slice).get().scope()); - assertEquals(slice.asOverlappingSlice(s1).get().byteSize(), slice.byteSize()); - assertEquals(slice.asOverlappingSlice(s1).get().scope(), slice.scope()); + assertEquals(slice.byteSize(), slice.asOverlappingSlice(s1).get().byteSize()); + assertEquals(slice.scope(), slice.asOverlappingSlice(s1).get().scope()); if (s1.isNative()) { - assertEquals(s1.asOverlappingSlice(slice).get().address(), s1.address() + offset); - assertEquals(slice.asOverlappingSlice(s1).get().address(), slice.address()); + assertEquals(s1.address() + offset, s1.asOverlappingSlice(slice).get().address()); + assertEquals(slice.address(), slice.asOverlappingSlice(s1).get().address()); } assertTrue(s2.asOverlappingSlice(slice).isEmpty()); } diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index e9f3e8a87cc2..a8d3b73f54e1 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,11 @@ * @test * @requires vm.bits == 64 * @modules java.base/sun.nio.ch - * @run testng/othervm -Xmx4G -XX:MaxDirectMemorySize=1M --enable-native-access=ALL-UNNAMED TestSegments + * @run junit/othervm -Xmx4G -XX:MaxDirectMemorySize=1M --enable-native-access=ALL-UNNAMED TestSegments */ import java.lang.foreign.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; @@ -45,20 +43,29 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSegments { - @Test(dataProvider = "badSizeAndAlignments", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("sizesAndAlignments") public void testBadAllocateAlign(long size, long align) { - Arena.ofAuto().allocate(size, align); + assertThrows(IllegalArgumentException.class, () -> { + Arena.ofAuto().allocate(size, align); + }); } @Test public void testZeroLengthNativeSegment() { try (Arena arena = Arena.ofConfined()) { var segment = arena.allocate(0, 1); - assertEquals(segment.byteSize(), 0); + assertEquals(0, segment.byteSize()); if (segment.address() == 0) { fail("Segment address is zero"); } @@ -67,14 +74,14 @@ public void testZeroLengthNativeSegment() { } MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT); segment = arena.allocate(seq); - assertEquals(segment.byteSize(), 0); - assertEquals(segment.address() % seq.byteAlignment(), 0); + assertEquals(0, segment.byteSize()); + assertEquals(0, segment.address() % seq.byteAlignment()); segment = arena.allocate(0, 4); - assertEquals(segment.byteSize(), 0); - assertEquals(segment.address() % 4, 0); + assertEquals(0, segment.byteSize()); + assertEquals(0, segment.address() % 4); MemorySegment rawAddress = MemorySegment.ofAddress(segment.address()); - assertEquals(rawAddress.byteSize(), 0); - assertEquals(rawAddress.address() % 4, 0); + assertEquals(0, rawAddress.byteSize()); + assertEquals(0, rawAddress.address() % 4); } } @@ -83,7 +90,7 @@ public void testZeroLengthNativeSegmentHyperAligned() { long byteAlignment = 1024; try (Arena arena = Arena.ofConfined()) { var segment = arena.allocate(0, byteAlignment); - assertEquals(segment.byteSize(), 0); + assertEquals(0, segment.byteSize()); if (segment.address() == 0) { fail("Segment address is zero"); } @@ -91,17 +98,21 @@ public void testZeroLengthNativeSegmentHyperAligned() { } } - - @Test(expectedExceptions = { OutOfMemoryError.class, - IllegalArgumentException.class }) + @Test public void testAllocateTooBig() { - Arena.ofAuto().allocate(Long.MAX_VALUE, 1); + // One of two ex. types may be thrown. Throwable is common ancestor. + Throwable t = assertThrows(Throwable.class, + () -> Arena.ofAuto().allocate(Long.MAX_VALUE, 1)); + // must be either + assertTrue(t instanceof OutOfMemoryError || t instanceof IllegalArgumentException); } - @Test(expectedExceptions = OutOfMemoryError.class) + @Test public void testNativeAllocationTooBig() { - Arena scope = Arena.ofAuto(); - MemorySegment segment = scope.allocate(1024L * 1024 * 8 * 2, 1); // 2M + assertThrows(OutOfMemoryError.class, () -> { + Arena scope = Arena.ofAuto(); + MemorySegment segment = scope.allocate(1024L * 1024 * 8 * 2, 1); // 2M + }); } @Test @@ -127,88 +138,91 @@ public void testSlices() { for (int offset = 0 ; offset < 10 ; offset++) { MemorySegment slice = segment.asSlice(offset); for (long i = offset ; i < 10 ; i++) { - assertEquals( - byteHandle.get(segment, i), - byteHandle.get(slice, i - offset) + assertEquals( byteHandle.get(slice, i - offset), byteHandle.get(segment, i) ); } } } } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testDerivedScopes(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); assertEquals(segment.scope(), segment.scope()); // one level - assertEquals(segment.asSlice(0).scope(), segment.scope()); - assertEquals(segment.asReadOnly().scope(), segment.scope()); + assertEquals(segment.scope(), segment.asSlice(0).scope()); + assertEquals(segment.scope(), segment.asReadOnly().scope()); // two levels - assertEquals(segment.asSlice(0).asReadOnly().scope(), segment.scope()); - assertEquals(segment.asReadOnly().asSlice(0).scope(), segment.scope()); + assertEquals(segment.scope(), segment.asSlice(0).asReadOnly().scope()); + assertEquals(segment.scope(), segment.asReadOnly().asSlice(0).scope()); // check fresh every time MemorySegment another = segmentSupplier.get(); - assertNotEquals(segment.scope(), another.scope()); + assertNotEquals(another.scope(), segment.scope()); } @Test public void testEqualsOffHeap() { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(100, 1); - assertEquals(segment, segment.asReadOnly()); - assertEquals(segment, segment.asSlice(0, 100)); - assertNotEquals(segment, segment.asSlice(10, 90)); - assertEquals(segment, segment.asSlice(0, 90)); - assertEquals(segment, MemorySegment.ofAddress(segment.address())); + assertEquals(segment.asReadOnly(), segment); + assertEquals(segment.asSlice(0, 100), segment); + assertNotEquals(segment.asSlice(10, 90), segment); + assertEquals(segment.asSlice(0, 90), segment); + assertEquals(MemorySegment.ofAddress(segment.address()), segment); MemorySegment segment2 = arena.allocate(100, 1); - assertNotEquals(segment, segment2); + assertNotEquals(segment2, segment); } } @Test public void testEqualsOnHeap() { MemorySegment segment = MemorySegment.ofArray(new byte[100]); - assertEquals(segment, segment.asReadOnly()); - assertEquals(segment, segment.asSlice(0, 100)); - assertNotEquals(segment, segment.asSlice(10, 90)); - assertEquals(segment, segment.asSlice(0, 90)); + assertEquals(segment.asReadOnly(), segment); + assertEquals(segment.asSlice(0, 100), segment); + assertNotEquals(segment.asSlice(10, 90), segment); + assertEquals(segment.asSlice(0, 90), segment); MemorySegment segment2 = MemorySegment.ofArray(new byte[100]); - assertNotEquals(segment, segment2); + assertNotEquals(segment2, segment); } @Test public void testHashCodeOffHeap() { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(100, 1); - assertEquals(segment.hashCode(), segment.asReadOnly().hashCode()); - assertEquals(segment.hashCode(), segment.asSlice(0, 100).hashCode()); - assertEquals(segment.hashCode(), segment.asSlice(0, 90).hashCode()); - assertEquals(segment.hashCode(), MemorySegment.ofAddress(segment.address()).hashCode()); + assertEquals(segment.asReadOnly().hashCode(), segment.hashCode()); + assertEquals(segment.asSlice(0, 100).hashCode(), segment.hashCode()); + assertEquals(segment.asSlice(0, 90).hashCode(), segment.hashCode()); + assertEquals(MemorySegment.ofAddress(segment.address()).hashCode(), segment.hashCode()); } } @Test public void testHashCodeOnHeap() { MemorySegment segment = MemorySegment.ofArray(new byte[100]); - assertEquals(segment.hashCode(), segment.asReadOnly().hashCode()); - assertEquals(segment.hashCode(), segment.asSlice(0, 100).hashCode()); - assertEquals(segment.hashCode(), segment.asSlice(0, 90).hashCode()); + assertEquals(segment.asReadOnly().hashCode(), segment.hashCode()); + assertEquals(segment.asSlice(0, 100).hashCode(), segment.hashCode()); + assertEquals(segment.asSlice(0, 90).hashCode(), segment.hashCode()); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSmallSegmentMax() { long offset = (long)Integer.MAX_VALUE + (long)Integer.MAX_VALUE + 2L + 6L; // overflows to 6 when cast to int Arena scope = Arena.ofAuto(); MemorySegment memorySegment = scope.allocate(10, 1); - memorySegment.get(JAVA_INT, offset); + assertThrows(IndexOutOfBoundsException.class, () -> { + memorySegment.get(JAVA_INT, offset); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSmallSegmentMin() { long offset = ((long)Integer.MIN_VALUE * 2L) + 6L; // underflows to 6 when cast to int Arena scope = Arena.ofAuto(); MemorySegment memorySegment = scope.allocate(10L, 1); - memorySegment.get(JAVA_INT, offset); + assertThrows(IndexOutOfBoundsException.class, () -> { + memorySegment.get(JAVA_INT, offset); + }); } @Test @@ -241,13 +255,13 @@ public void testSegmentSliceOOBMessage() { } } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testAccessModesOfFactories(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); assertFalse(segment.isReadOnly()); } - @DataProvider(name = "scopes") public Object[][] scopes() { return new Object[][] { { Arena.ofAuto(), false }, @@ -257,14 +271,16 @@ public Object[][] scopes() { }; } - @Test(dataProvider = "scopes") + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("scopes") public void testIsAccessibleBy(Arena arena, boolean isConfined) { MemorySegment segment = MemorySegment.NULL.reinterpret(arena, null); assertTrue(segment.isAccessibleBy(Thread.currentThread())); assertTrue(segment.isAccessibleBy(new Thread()) != isConfined); } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testToString(Supplier segmentSupplier) { var segment = segmentSupplier.get(); String s = segment.toString(); @@ -281,7 +297,6 @@ public void testToString(Supplier segmentSupplier) { assertFalse(s.contains("Optional")); } - @DataProvider(name = "segmentFactories") public Object[][] segmentFactories() { List> l = List.of( () -> MemorySegment.ofArray(new byte[] { 0x00, 0x01, 0x02, 0x03 }), @@ -302,7 +317,8 @@ public Object[][] segmentFactories() { return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testFill(Supplier segmentSupplier) { VarHandle byteHandle = ValueLayout.JAVA_BYTE.varHandle(); @@ -310,27 +326,28 @@ public void testFill(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); segment.fill(value); for (long l = 0; l < segment.byteSize(); l++) { - assertEquals((byte) byteHandle.get(segment, l), value); + assertEquals(value, (byte) byteHandle.get(segment, l)); } // fill a slice var sliceSegment = segment.asSlice(1, segment.byteSize() - 2).fill((byte) ~value); for (long l = 0; l < sliceSegment.byteSize(); l++) { - assertEquals((byte) byteHandle.get(sliceSegment, l), ~value); + assertEquals(~value, (byte) byteHandle.get(sliceSegment, l)); } // assert enclosing slice - assertEquals((byte) byteHandle.get(segment, 0L), value); + assertEquals(value, (byte) byteHandle.get(segment, 0L)); for (long l = 1; l < segment.byteSize() - 2; l++) { - assertEquals((byte) byteHandle.get(segment, l), (byte) ~value); + assertEquals((byte) ~value, (byte) byteHandle.get(segment, l)); } - assertEquals((byte) byteHandle.get(segment, segment.byteSize() - 1L), value); + assertEquals(value, (byte) byteHandle.get(segment, segment.byteSize() - 1L)); } } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testHeapBase(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); - assertEquals(segment.isNative(), !segment.heapBase().isPresent()); + assertEquals(!segment.heapBase().isPresent(), segment.isNative()); segment = segment.asReadOnly(); assertTrue(segment.heapBase().isEmpty()); } @@ -339,7 +356,7 @@ public void testHeapBase(Supplier segmentSupplier) { public void testScopeConfinedArena() { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(100); - assertEquals(segment.scope(), arena.scope()); + assertEquals(arena.scope(), segment.scope()); } } @@ -347,7 +364,7 @@ public void testScopeConfinedArena() { public void testScopeSharedArena() { try (Arena arena = Arena.ofShared()) { MemorySegment segment = arena.allocate(100); - assertEquals(segment.scope(), arena.scope()); + assertEquals(arena.scope(), segment.scope()); } } @@ -355,29 +372,36 @@ public void testScopeSharedArena() { public void testScopeAutoArena() { Arena arena = Arena.ofAuto(); MemorySegment segment = arena.allocate(100); - assertEquals(segment.scope(), arena.scope()); + assertEquals(arena.scope(), segment.scope()); } @Test public void testScopeGlobalArena() { Arena arena = Arena.global(); MemorySegment segment = arena.allocate(100); - assertEquals(segment.scope(), arena.scope()); + assertEquals(arena.scope(), segment.scope()); } - @Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("segmentFactories") public void testFillIllegalAccessMode(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); - segment.asReadOnly().fill((byte) 0xFF); + assertThrows(IllegalArgumentException.class, () -> { + segment.asReadOnly().fill((byte) 0xFF); + }); } - @Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("segmentFactories") public void testFromStringIllegalAccessMode(Supplier segmentSupplier) { MemorySegment segment = segmentSupplier.get(); - segment.asReadOnly().setString(0, "a"); + assertThrows(IllegalArgumentException.class, () -> { + segment.asReadOnly().setString(0, "a"); + }); } - @Test(dataProvider = "segmentFactories") + @ParameterizedTest + @MethodSource("segmentFactories") public void testFillThread(Supplier segmentSupplier) throws Exception { MemorySegment segment = segmentSupplier.get(); AtomicReference exception = new AtomicReference<>(); @@ -407,12 +431,13 @@ public void testFillEmpty() { MemorySegment.ofBuffer(ByteBuffer.allocateDirect(0)).fill((byte) 0xFF); } - @Test(dataProvider = "heapFactories") + @ParameterizedTest + @MethodSource("heapFactories") public void testVirtualizedBaseAddress(IntFunction heapSegmentFactory, int factor) { MemorySegment segment = heapSegmentFactory.apply(10); - assertEquals(segment.address(), 0); // base address should be zero (no leaking of impl details) + assertEquals(0, segment.address()); // base address should be zero (no leaking of impl details) MemorySegment end = segment.asSlice(segment.byteSize(), 0); - assertEquals(end.address(), segment.byteSize()); // end address should be equal to segment byte size + assertEquals(segment.byteSize(), end.address()); // end address should be equal to segment byte size } @Test @@ -420,18 +445,18 @@ void testReinterpret() { AtomicInteger counter = new AtomicInteger(); try (Arena arena = Arena.ofConfined()){ // check size - assertEquals(MemorySegment.ofAddress(42).reinterpret(100).byteSize(), 100); - assertEquals(MemorySegment.ofAddress(42).reinterpret(100, Arena.ofAuto(), null).byteSize(), 100); + assertEquals(100, MemorySegment.ofAddress(42).reinterpret(100).byteSize()); + assertEquals(100, MemorySegment.ofAddress(42).reinterpret(100, Arena.ofAuto(), null).byteSize()); // check scope and cleanup - assertEquals(MemorySegment.ofAddress(42).reinterpret(100, arena, s -> counter.incrementAndGet()).scope(), arena.scope()); - assertEquals(MemorySegment.ofAddress(42).reinterpret(arena, _ -> counter.incrementAndGet()).scope(), arena.scope()); + assertEquals(arena.scope(), MemorySegment.ofAddress(42).reinterpret(100, arena, s -> counter.incrementAndGet()).scope()); + assertEquals(arena.scope(), MemorySegment.ofAddress(42).reinterpret(arena, _ -> counter.incrementAndGet()).scope()); // check read-only state assertFalse(MemorySegment.ofAddress(42).reinterpret(100).isReadOnly()); assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100).isReadOnly()); assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100, Arena.ofAuto(), null).isReadOnly()); assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(arena, _ -> counter.incrementAndGet()).isReadOnly()); } - assertEquals(counter.get(), 3); + assertEquals(3, counter.get()); } @Test @@ -477,8 +502,8 @@ void testThrowInCleanup() { thrown = ex; } assertNotNull(thrown); - assertEquals(counter.get(), 1); - assertEquals(thrown.getSuppressed().length, 19); + assertEquals(1, counter.get()); + assertEquals(19, thrown.getSuppressed().length); Throwable[] errors = new IllegalArgumentException[20]; assertTrue(thrown instanceof IllegalArgumentException); errors[0] = thrown; @@ -512,12 +537,11 @@ void testThrowInCleanupSame() { } catch (RuntimeException ex) { thrown = ex; } - assertEquals(thrown, iae); - assertEquals(counter.get(), 1); - assertEquals(thrown.getSuppressed().length, 0); + assertEquals(iae, thrown); + assertEquals(1, counter.get()); + assertEquals(0, thrown.getSuppressed().length); } - @DataProvider(name = "badSizeAndAlignments") public Object[][] sizesAndAlignments() { return new Object[][] { { -1, 8 }, @@ -526,7 +550,6 @@ public Object[][] sizesAndAlignments() { }; } - @DataProvider(name = "heapFactories") public Object[][] heapFactories() { return new Object[][] { { (IntFunction) size -> MemorySegment.ofArray(new byte[size]), 1 }, diff --git a/test/jdk/java/foreign/TestSharedAccess.java b/test/jdk/java/foreign/TestSharedAccess.java index 9823f6f0bbfb..093f20cd96aa 100644 --- a/test/jdk/java/foreign/TestSharedAccess.java +++ b/test/jdk/java/foreign/TestSharedAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestSharedAccess + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestSharedAccess */ import java.lang.foreign.*; @@ -37,9 +37,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestSharedAccess { @@ -74,7 +73,7 @@ public void testShared() throws Throwable { for (Spliterator spliterator : spliterators) { threads.add(new Thread(() -> { spliterator.tryAdvance(local -> { - assertEquals(getInt(local), 42); + assertEquals(42, getInt(local)); accessCount.incrementAndGet(); }); })); @@ -87,7 +86,7 @@ public void testShared() throws Throwable { throw new IllegalStateException(e); } }); - assertEquals(accessCount.get(), 1024); + assertEquals(1024, accessCount.get()); } } @@ -96,11 +95,11 @@ public void testSharedUnsafe() throws Throwable { try (Arena arena = Arena.ofShared()) { MemorySegment s = arena.allocate(4, 1);; setInt(s, 42); - assertEquals(getInt(s), 42); + assertEquals(42, getInt(s)); List threads = new ArrayList<>(); for (int i = 0 ; i < 1000 ; i++) { threads.add(new Thread(() -> { - assertEquals(getInt(s), 42); + assertEquals(42, getInt(s)); })); } threads.forEach(Thread::start); diff --git a/test/jdk/java/foreign/TestSlices.java b/test/jdk/java/foreign/TestSlices.java index 88fe98cc847e..d2ba96ae94ba 100644 --- a/test/jdk/java/foreign/TestSlices.java +++ b/test/jdk/java/foreign/TestSlices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,17 @@ import java.util.ArrayList; import java.util.List; -import org.testng.annotations.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test - * @run testng/othervm -Xverify:all TestSlices + * @run junit/othervm -Xverify:all TestSlices */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSlices { static MemoryLayout LAYOUT = MemoryLayout.sequenceLayout(2, @@ -45,7 +49,8 @@ public class TestSlices { static VarHandle VH_ALL = LAYOUT.varHandle( MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement()); - @Test(dataProvider = "slices") + @ParameterizedTest + @MethodSource("slices") public void testSlices(VarHandle handle, int lo, int hi, int[] values) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(LAYOUT);; @@ -60,12 +65,13 @@ public void testSlices(VarHandle handle, int lo, int hi, int[] values) { } } - @Test(dataProvider = "slices") + @ParameterizedTest + @MethodSource("slices") public void testSliceBadIndex(VarHandle handle, int lo, int hi, int[] values) { try (Arena arena = Arena.ofConfined()) { MemorySegment segment = arena.allocate(LAYOUT);; - assertThrows(() -> handle.get(segment, 0L, lo, 0)); - assertThrows(() -> handle.get(segment, 0L, 0, hi)); + assertThrows(Throwable.class, () -> handle.get(segment, 0L, lo, 0)); + assertThrows(Throwable.class, () -> handle.get(segment, 0L, 0, hi)); } } @@ -74,54 +80,71 @@ static void checkSlice(MemorySegment segment, VarHandle handle, long i_max, long for (long i = 0 ; i < i_max ; i++) { for (long j = 0 ; j < j_max ; j++) { int x = (int) handle.get(segment, 0L, i, j); - assertEquals(x, values[index++]); + assertEquals(values[index++], x); } } - assertEquals(index, values.length); + assertEquals(values.length, index); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceNegativeOffset() { - MemorySegment.ofArray(new byte[100]).asSlice(-1); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(-1); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceNegativeOffsetGoodSize() { - MemorySegment.ofArray(new byte[100]).asSlice(-1, 10); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(-1, 10); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceGoodOffsetNegativeSize() { - MemorySegment.ofArray(new byte[100]).asSlice(10, -1); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(10, -1); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceNegativeOffsetGoodLayout() { - MemorySegment.ofArray(new byte[100]).asSlice(-1, ValueLayout.JAVA_INT); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(-1, ValueLayout.JAVA_INT); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceOffsetTooBig() { - MemorySegment.ofArray(new byte[100]).asSlice(120); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(120); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceOffsetTooBigSizeGood() { - MemorySegment.ofArray(new byte[100]).asSlice(120, 0); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(120, 0); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceOffsetOkSizeTooBig() { - MemorySegment.ofArray(new byte[100]).asSlice(0, 120); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]).asSlice(0, 120); + }); } - @Test(expectedExceptions = IndexOutOfBoundsException.class) + @Test public void testSliceLayoutTooBig() { - MemorySegment.ofArray(new byte[100]) - .asSlice(0, MemoryLayout.sequenceLayout(120, ValueLayout.JAVA_BYTE)); + assertThrows(IndexOutOfBoundsException.class, () -> { + MemorySegment.ofArray(new byte[100]) + .asSlice(0, MemoryLayout.sequenceLayout(120, ValueLayout.JAVA_BYTE)); + }); } - @Test(dataProvider = "segmentsAndLayouts") + @ParameterizedTest + @MethodSource("segmentsAndLayouts") public void testSliceAlignment(MemorySegment segment, long alignment, ValueLayout layout) { boolean badAlign = layout.byteAlignment() > alignment; try { @@ -149,7 +172,6 @@ public void testSliceAlignmentPowerOfTwo() { } } - @DataProvider(name = "slices") static Object[][] slices() { return new Object[][] { // x @@ -169,7 +191,6 @@ static Object[][] slices() { }; } - @DataProvider(name = "segmentsAndLayouts") static Object[][] segmentsAndLayouts() { List segmentsAndLayouts = new ArrayList<>(); for (SegmentKind sk : SegmentKind.values()) { diff --git a/test/jdk/java/foreign/TestSpliterator.java b/test/jdk/java/foreign/TestSpliterator.java index 285e8ab27ea0..074615218c91 100644 --- a/test/jdk/java/foreign/TestSpliterator.java +++ b/test/jdk/java/foreign/TestSpliterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng TestSpliterator + * @run junit TestSpliterator */ import java.lang.foreign.*; @@ -35,15 +35,19 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.LongStream; -import org.testng.annotations.*; - -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSpliterator { final static int CARRIER_SIZE = 4; - @Test(dataProvider = "splits") + @ParameterizedTest + @MethodSource("splits") public void testSum(int size, int threshold) { SequenceLayout layout = MemoryLayout.sequenceLayout(size, ValueLayout.JAVA_INT); @@ -56,17 +60,17 @@ public void testSum(int size, int threshold) { long expected = LongStream.range(0, layout.elementCount()).sum(); //serial long serial = sum(0, segment); - assertEquals(serial, expected); + assertEquals(expected, serial); //parallel counted completer long parallelCounted = new SumSegmentCounted(null, segment.spliterator(layout.elementLayout()), threshold).invoke(); - assertEquals(parallelCounted, expected); + assertEquals(expected, parallelCounted); //parallel recursive action long parallelRecursive = new SumSegmentRecursive(segment.spliterator(layout.elementLayout()), threshold).invoke(); - assertEquals(parallelRecursive, expected); + assertEquals(expected, parallelRecursive); //parallel stream long streamParallel = segment.elements(layout.elementLayout()).parallel() .reduce(0L, TestSpliterator::sumSingle, Long::sum); - assertEquals(streamParallel, expected); + assertEquals(expected, streamParallel); } } @@ -86,35 +90,39 @@ public void testSumSameThread() { AtomicLong spliteratorSum = new AtomicLong(); segment.spliterator(layout.elementLayout()) .forEachRemaining(s -> spliteratorSum.addAndGet(sumSingle(0L, s))); - assertEquals(spliteratorSum.get(), expected); + assertEquals(expected, spliteratorSum.get()); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadSpliteratorElementSizeTooBig() { - Arena scope = Arena.ofAuto(); - scope.allocate(2, 1) - .spliterator(ValueLayout.JAVA_INT); + MemorySegment segment = Arena.ofAuto().allocate(2, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.spliterator(ValueLayout.JAVA_INT); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadStreamElementSizeTooBig() { - Arena scope = Arena.ofAuto(); - scope.allocate(2, 1) - .elements(ValueLayout.JAVA_INT); + MemorySegment segment = Arena.ofAuto().allocate(2, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.elements(ValueLayout.JAVA_INT); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadSpliteratorElementSizeNotMultiple() { - Arena scope = Arena.ofAuto(); - scope.allocate(7, 1) - .spliterator(ValueLayout.JAVA_INT); + MemorySegment segment = Arena.ofAuto().allocate(7, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.spliterator(ValueLayout.JAVA_INT); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadStreamElementSizeNotMultiple() { - Arena scope = Arena.ofAuto(); - scope.allocate(7, 1) - .elements(ValueLayout.JAVA_INT); + MemorySegment segment = Arena.ofAuto().allocate(7, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.elements(ValueLayout.JAVA_INT); + }); } @Test @@ -131,18 +139,20 @@ public void testStreamElementSizeMultipleButNotPowerOfTwo() { .elements(ValueLayout.JAVA_INT); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadSpliteratorElementSizeZero() { - Arena scope = Arena.ofAuto(); - scope.allocate(7, 1) - .spliterator(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); + MemorySegment segment = Arena.ofAuto().allocate(7, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.spliterator(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testBadStreamElementSizeZero() { - Arena scope = Arena.ofAuto(); - scope.allocate(7, 1) - .elements(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); + MemorySegment segment = Arena.ofAuto().allocate(7, 1); + assertThrows(IllegalArgumentException.class, () -> { + segment.elements(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT)); + }); } @Test @@ -155,9 +165,9 @@ public void testHyperAligned() { Collections.nCopies(Math.toIntExact(bigByteAlign), ValueLayout.JAVA_BYTE).toArray(MemoryLayout[]::new)) .withByteAlignment(bigByteAlign); SequenceLayout layout = MemoryLayout.sequenceLayout(2, elementLayout); - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> segment.elements(layout)); - assertEquals(iae.getMessage(), "Incompatible alignment constraints"); + assertEquals("Incompatible alignment constraints", iae.getMessage()); } static long sumSingle(long acc, MemorySegment segment) { @@ -239,7 +249,6 @@ protected Long compute() { } } - @DataProvider(name = "splits") public Object[][] splits() { return new Object[][] { { 10, 1 }, diff --git a/test/jdk/java/foreign/TestStringEncoding.java b/test/jdk/java/foreign/TestStringEncoding.java index e9e47420a684..c2a9131941bf 100644 --- a/test/jdk/java/foreign/TestStringEncoding.java +++ b/test/jdk/java/foreign/TestStringEncoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,17 +42,22 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.StringSupport; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test * @modules java.base/jdk.internal.foreign - * @run testng TestStringEncoding + * @run junit TestStringEncoding */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestStringEncoding { @Test @@ -61,7 +66,7 @@ public void emptySegment() { for (Arena arena : arenas()) { try (arena) { var segment = arena.allocate(0); - var e = expectThrows(IndexOutOfBoundsException.class, () -> + var e = assertThrows(IndexOutOfBoundsException.class, () -> segment.getString(0, charset)); assertTrue(e.getMessage().contains("No null terminator found")); } @@ -69,7 +74,8 @@ public void emptySegment() { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testStrings(String testString) { for (Charset charset : Charset.availableCharsets().values()) { if (isStandard(charset)) { @@ -89,11 +95,11 @@ public void testStrings(String testString) { testString.getBytes(charset).length + terminatorSize; - assertEquals(text.byteSize(), expectedByteLength); + assertEquals(expectedByteLength, text.byteSize()); String roundTrip = text.getString(0, charset); if (charset.newEncoder().canEncode(testString)) { - assertEquals(roundTrip, testString); + assertEquals(testString, roundTrip); } } } @@ -103,7 +109,8 @@ public void testStrings(String testString) { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testStringsLength(String testString) { if (!testString.isEmpty()) { for (Charset charset : Charset.availableCharsets().values()) { @@ -112,10 +119,10 @@ public void testStringsLength(String testString) { try (arena) { MemorySegment text = arena.allocateFrom(testString, charset, 0, testString.length()); long length = text.byteSize(); - assertEquals(length, testString.getBytes(charset).length); + assertEquals(testString.getBytes(charset).length, length); String roundTrip = text.getString(0, charset, length); if (charset.newEncoder().canEncode(testString)) { - assertEquals(roundTrip, testString); + assertEquals(testString, roundTrip); } } } @@ -124,7 +131,8 @@ public void testStringsLength(String testString) { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testStringsCopy(String testString) { if (!testString.isEmpty()) { for (Charset charset : Charset.availableCharsets().values()) { @@ -136,7 +144,7 @@ public void testStringsCopy(String testString) { MemorySegment.copy(testString, charset, 0, text, 0, testString.length()); String roundTrip = text.getString(0, charset, bytes.length); if (charset.newEncoder().canEncode(testString)) { - assertEquals(roundTrip, testString); + assertEquals(testString, roundTrip); } } } @@ -237,7 +245,8 @@ public void testGetStringThrows() { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testStringsHeap(String testString) { for (Charset charset : singleByteCharsets()) { for (var arena : arenas()) { @@ -248,11 +257,11 @@ public void testStringsHeap(String testString) { int expectedByteLength = testString.getBytes(charset).length + 1; - assertEquals(text.byteSize(), expectedByteLength); + assertEquals(expectedByteLength, text.byteSize()); String roundTrip = text.getString(0, charset); if (charset.newEncoder().canEncode(testString)) { - assertEquals(roundTrip, testString); + assertEquals(testString, roundTrip); } } } @@ -264,7 +273,8 @@ MemorySegment toHeapSegment(MemorySegment segment) { return MemorySegment.ofArray(heapArray); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void unboundedSegment(String testString) { testModifyingSegment(testString, standardCharsets(), @@ -272,7 +282,8 @@ public void unboundedSegment(String testString) { UnaryOperator.identity()); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void unalignedSegmentSingleByte(String testString) { testModifyingSegment(testString, singleByteCharsets(), @@ -280,7 +291,8 @@ public void unalignedSegmentSingleByte(String testString) { s -> s.length() > 0 ? s.substring(1) : s); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void expandedSegment(String testString) { try (var arena = Arena.ofConfined()) { for (int i = 0; i < Long.BYTES; i++) { @@ -309,7 +321,7 @@ public void testModifyingSegment(String testString, String roundTrip = text.getString(0, charset); String expected = stringMapper.apply(testString); if (charset.newEncoder().canEncode(testString)) { - assertEquals(roundTrip, expected); + assertEquals(expected, roundTrip); } } } @@ -330,14 +342,15 @@ public void testPeculiarContentSingleByte() { for (Charset charset : singleByteCharsets()) { var s = segment.getString(0, charset); var ref = referenceImpl(segment, 0, charset); - assertEquals(s, ref); + assertEquals(ref, s); } } } } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testOffset(String testString) { if (testString.length() < 3 || !containsOnlyRegularCharacters(testString)) { return; @@ -349,14 +362,15 @@ public void testOffset(String testString) { for (int i = 0; i < 3; i++) { String expected = testString.substring(i); String actual = inSegment.getString(i, charset); - assertEquals(actual, expected); + assertEquals(expected, actual); } } } } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testSubstringGetString(String testString) { if (testString.length() < 3 || !containsOnlyRegularCharacters(testString)) { return; @@ -370,7 +384,7 @@ public void testSubstringGetString(String testString) { // this test assumes single-byte charsets String roundTrip = text.getString(srcIndex, charset, numChars); String substring = testString.substring(srcIndex, srcIndex + numChars); - assertEquals(roundTrip, substring); + assertEquals(substring, roundTrip); } } } @@ -378,7 +392,8 @@ public void testSubstringGetString(String testString) { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testSubstringAllocate(String testString) { if (testString.length() < 3 || !containsOnlyRegularCharacters(testString)) { return; @@ -390,9 +405,9 @@ public void testSubstringAllocate(String testString) { for (int numChars = 0; numChars <= testString.length() - srcIndex; numChars++) { MemorySegment text = arena.allocateFrom(testString, charset, srcIndex, numChars); String substring = testString.substring(srcIndex, srcIndex + numChars); - assertEquals(text.byteSize(), substring.getBytes(charset).length); + assertEquals(substring.getBytes(charset).length, text.byteSize()); String roundTrip = text.getString(0, charset, text.byteSize()); - assertEquals(roundTrip, substring); + assertEquals(substring, roundTrip); } } } @@ -400,7 +415,8 @@ public void testSubstringAllocate(String testString) { } } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void testSubstringCopy(String testString) { if (testString.length() < 3 || !containsOnlyRegularCharacters(testString)) { return; @@ -415,8 +431,8 @@ public void testSubstringCopy(String testString) { MemorySegment text = arena.allocate(JAVA_BYTE, length); long copied = MemorySegment.copy(testString, charset, srcIndex, text, 0, numChars); String roundTrip = text.getString(0, charset, length); - assertEquals(roundTrip, substring); - assertEquals(copied, length); + assertEquals(substring, roundTrip); + assertEquals(length, copied); } } } @@ -431,7 +447,8 @@ public void testSubstringCopy(String testString) { LINKER.defaultLookup().find("strcat").orElseThrow(), FunctionDescriptor.of(CHAR_POINTER, CHAR_POINTER, CHAR_POINTER)); - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void nativeSegFromNativeCall(String testString) { String addition = "123"; try (var arena = Arena.ofConfined()) { @@ -443,7 +460,7 @@ public void nativeSegFromNativeCall(String testString) { MemorySegment concatenation = (MemorySegment) STRCAT.invokeExact(destination, arena.allocateFrom(addition)); var actual = concatenation.getString(0); - assertEquals(actual, testString + addition); + assertEquals(testString + addition, actual); } catch (Throwable t) { throw new AssertionError(t); } @@ -469,7 +486,8 @@ public void segmentationFault() { // This test ensures that we do not address outside the segment even though there // are odd bytes at the end. - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void offBoundaryTrailingBytes(String testString) { if (testString.length() < 3 || !containsOnlyRegularCharacters(testString)) { return; @@ -485,7 +503,7 @@ public void offBoundaryTrailingBytes(String testString) { inSegment.fill((byte) 1); for (int i = 0; i < 4; i++) { final int offset = i; - var e = expectThrows(IndexOutOfBoundsException.class, () -> inSegment.getString(offset, charset)); + var e = assertThrows(IndexOutOfBoundsException.class, () -> inSegment.getString(offset, charset)); assertTrue(e.getMessage().contains("No null terminator found")); } } @@ -516,12 +534,12 @@ public void chunked_strlen_byte() { segment.setAtIndex(JAVA_BYTE, len, (byte) 0); for (int j = 0; j < len; j++) { int actual = StringSupport.strlenByte((AbstractMemorySegmentImpl) segment, j, segment.byteSize()); - assertEquals(actual, len - j); + assertEquals(len - j, actual); } // Test end offset for (int j = 0; j < len - 1; j++) { final long toOffset = j; - expectThrows(IndexOutOfBoundsException.class, () -> + assertThrows(IndexOutOfBoundsException.class, () -> StringSupport.strlenByte((AbstractMemorySegmentImpl) segment, 0, toOffset)); } } @@ -546,7 +564,7 @@ public void chunked_strlen_short() { segment.setAtIndex(JAVA_SHORT, len, (short) 0); for (int j = 0; j < len; j++) { int actual = StringSupport.strlenShort((AbstractMemorySegmentImpl) segment, j * Short.BYTES, segment.byteSize()); - assertEquals(actual, (len - j) * Short.BYTES); + assertEquals((len - j) * Short.BYTES, actual); } } } @@ -570,35 +588,37 @@ public void strlen_int() { segment.setAtIndex(JAVA_INT, len, 0); for (int j = 0; j < len; j++) { int actual = StringSupport.strlenInt((AbstractMemorySegmentImpl) segment, j * Integer.BYTES, segment.byteSize()); - assertEquals(actual, (len - j) * Integer.BYTES); + assertEquals((len - j) * Integer.BYTES, actual); } } } } } - @Test(dataProvider = "charsetsAndSegments") + @ParameterizedTest + @MethodSource("charsetsAndSegments") public void testStringGetWithCharset(Charset charset, MemorySegment segment) { for (int offset = 0 ; offset < Long.BYTES ; offset++) { segment.getString(offset, charset); } } - @Test(dataProvider = "charsetsAndSegments") + @ParameterizedTest + @MethodSource("charsetsAndSegments") public void testStringSetWithCharset(Charset charset, MemorySegment segment) { for (int offset = 0 ; offset < Long.BYTES ; offset++) { segment.setString(offset, "H", charset); } } - @Test(dataProvider = "charsetsAndSegments") + @ParameterizedTest + @MethodSource("charsetsAndSegments") public void testStringAllocateFromWithCharset(Charset charset, MemorySegment segment) { for (int offset = 0 ; offset < Long.BYTES ; offset++) { SegmentAllocator.prefixAllocator(segment.asSlice(offset)).allocateFrom("H", charset); } } - @DataProvider public static Object[][] strings() { return new Object[][]{ {"testing"}, @@ -733,7 +753,6 @@ static MemorySegment[] heapSegments() { }; } - @DataProvider public static Object[][] charsetsAndSegments() { List values = new ArrayList<>(); for (Charset charset : standardCharsets()) { diff --git a/test/jdk/java/foreign/TestStringEncodingJumbo.java b/test/jdk/java/foreign/TestStringEncodingJumbo.java index bdae83bbd8b3..31f03768d36b 100644 --- a/test/jdk/java/foreign/TestStringEncodingJumbo.java +++ b/test/jdk/java/foreign/TestStringEncodingJumbo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,6 @@ * questions. */ -import org.testng.annotations.*; import java.io.IOException; import java.io.RandomAccessFile; @@ -34,7 +33,9 @@ import java.util.function.Consumer; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /* * @test @@ -42,7 +43,7 @@ * @requires sun.arch.data.model == "64" * @requires vm.flavor != "zero" * - * @run testng/othervm/timeout=480 -Xmx6G TestStringEncodingJumbo + * @run junit/othervm/timeout=480 -Xmx6G TestStringEncodingJumbo */ public class TestStringEncodingJumbo { @@ -53,7 +54,7 @@ public void testJumboSegment() { segment.fill((byte) 1); segment.set(JAVA_BYTE, Integer.MAX_VALUE + 10L, (byte) 0); String big = segment.getString(100); - assertEquals(big.length(), Integer.MAX_VALUE - (100 - 10)); + assertEquals(Integer.MAX_VALUE - (100 - 10), big.length()); }); } diff --git a/test/jdk/java/foreign/TestStubAllocFailure.java b/test/jdk/java/foreign/TestStubAllocFailure.java index 8cd4a61626e7..99cd4b5eced2 100644 --- a/test/jdk/java/foreign/TestStubAllocFailure.java +++ b/test/jdk/java/foreign/TestStubAllocFailure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" * @requires vm.compMode != "Xcomp" - * @run testng/othervm/native/timeout=480 + * @run junit/othervm/native/timeout=480 * --enable-native-access=ALL-UNNAMED * TestStubAllocFailure */ @@ -39,9 +39,8 @@ import java.util.function.Consumer; import java.util.stream.Stream; -import org.testng.annotations.Test; - -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; public class TestStubAllocFailure extends UpcallTestHelper { diff --git a/test/jdk/java/foreign/TestTypeAccess.java b/test/jdk/java/foreign/TestTypeAccess.java index 13d3eaf0c0f0..347c96905178 100644 --- a/test/jdk/java/foreign/TestTypeAccess.java +++ b/test/jdk/java/foreign/TestTypeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,61 +24,75 @@ /* * @test - * @run testng TestTypeAccess + * @run junit TestTypeAccess */ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import org.testng.annotations.*; import java.lang.invoke.VarHandle; import java.lang.invoke.WrongMethodTypeException; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; + public class TestTypeAccess { static final VarHandle INT_HANDLE = ValueLayout.JAVA_INT.varHandle(); static final VarHandle ADDR_HANDLE = ValueLayout.ADDRESS.varHandle(); - @Test(expectedExceptions=ClassCastException.class) + @Test public void testMemoryAddressCoordinateAsString() { - int v = (int)INT_HANDLE.get("string", 0L); + assertThrows(ClassCastException.class, () -> { + int v = (int)INT_HANDLE.get("string", 0L); + }); } - @Test(expectedExceptions=WrongMethodTypeException.class) + @Test public void testMemoryCoordinatePrimitive() { - int v = (int)INT_HANDLE.get(1); + assertThrows(WrongMethodTypeException.class, () -> { + int v = (int)INT_HANDLE.get(1); + }); } - @Test(expectedExceptions=ClassCastException.class) + @Test public void testMemoryAddressValueGetAsString() { try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(8, 8); - String address = (String)ADDR_HANDLE.get(s, 0L); + assertThrows(ClassCastException.class, () -> { + String address = (String)ADDR_HANDLE.get(s, 0L); + }); } } - @Test(expectedExceptions=ClassCastException.class) + @Test public void testMemoryAddressValueSetAsString() { try (Arena arena = Arena.ofConfined()) { - MemorySegment s = arena.allocate(8, 8);; - ADDR_HANDLE.set(s, 0L, "string"); + MemorySegment s = arena.allocate(8, 8); + assertThrows(ClassCastException.class, () -> { + ADDR_HANDLE.set(s, 0L, "string"); + }); } } - @Test(expectedExceptions=WrongMethodTypeException.class) + @Test public void testMemoryAddressValueGetAsPrimitive() { try (Arena arena = Arena.ofConfined()) { MemorySegment s = arena.allocate(8, 8); - int address = (int)ADDR_HANDLE.get(s, 0L); + assertThrows(WrongMethodTypeException.class, () -> { + int address = (int)ADDR_HANDLE.get(s, 0L); + }); } } - @Test(expectedExceptions=WrongMethodTypeException.class) + @Test public void testMemoryAddressValueSetAsPrimitive() { try (Arena arena = Arena.ofConfined()) { - MemorySegment s = arena.allocate(8, 8);; - ADDR_HANDLE.set(s, 1); + MemorySegment s = arena.allocate(8, 8); + assertThrows(WrongMethodTypeException.class, () -> { + ADDR_HANDLE.set(s, 1); + }); } } diff --git a/test/jdk/java/foreign/TestUpcallAsync.java b/test/jdk/java/foreign/TestUpcallAsync.java index b912b1cd79e5..54a6651aa591 100644 --- a/test/jdk/java/foreign/TestUpcallAsync.java +++ b/test/jdk/java/foreign/TestUpcallAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestUpcallAsync */ import java.lang.foreign.*; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -45,6 +44,11 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallAsync extends TestUpcallBase { static { @@ -52,7 +56,8 @@ public class TestUpcallAsync extends TestUpcallBase { System.loadLibrary("AsyncInvokers"); } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testUpcallsAsync(int count, String fName, Ret ret, List paramTypes, List fields) throws Throwable { List> returnChecks = new ArrayList<>(); List> argChecks = new ArrayList<>(); diff --git a/test/jdk/java/foreign/TestUpcallBase.java b/test/jdk/java/foreign/TestUpcallBase.java index e768ade8577c..cf0249857be1 100644 --- a/test/jdk/java/foreign/TestUpcallBase.java +++ b/test/jdk/java/foreign/TestUpcallBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class TestUpcallBase extends CallGeneratorHelper { static FunctionDescriptor function(Ret ret, List params, List fields) { diff --git a/test/jdk/java/foreign/TestUpcallException.java b/test/jdk/java/foreign/TestUpcallException.java index beaa33f5e61f..5bf2aaa86e78 100644 --- a/test/jdk/java/foreign/TestUpcallException.java +++ b/test/jdk/java/foreign/TestUpcallException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,11 @@ * @library /test/lib * @build TestUpcallException * - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * TestUpcallException */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.lang.foreign.Arena; @@ -43,16 +41,21 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallException extends UpcallTestHelper { - @Test(dataProvider = "exceptionCases") + @ParameterizedTest + @MethodSource("exceptionCases") public void testException(Class target, boolean useSpec) throws InterruptedException, IOException { runInNewProcess(target, useSpec) .shouldNotHaveExitValue(0) .stderrShouldContain("Testing upcall exceptions"); } - @DataProvider public static Object[][] exceptionCases() { return new Object[][]{ { VoidUpcallRunner.class, false }, diff --git a/test/jdk/java/foreign/TestUpcallHighArity.java b/test/jdk/java/foreign/TestUpcallHighArity.java index 7bb369c884d6..cf448b741a25 100644 --- a/test/jdk/java/foreign/TestUpcallHighArity.java +++ b/test/jdk/java/foreign/TestUpcallHighArity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallHighArity * - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * TestUpcallHighArity */ import java.lang.foreign.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; @@ -44,6 +42,11 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallHighArity extends CallGeneratorHelper { static final MethodHandle MH_do_upcall; @@ -59,7 +62,8 @@ public class TestUpcallHighArity extends CallGeneratorHelper { ); } - @Test(dataProvider = "args") + @ParameterizedTest + @MethodSource("args") public void testUpcall(MethodHandle downcall, MethodType upcallType, FunctionDescriptor upcallDescriptor) throws Throwable { AtomicReference capturedArgs = new AtomicReference<>(); @@ -83,7 +87,6 @@ public void testUpcall(MethodHandle downcall, MethodType upcallType, } } - @DataProvider public static Object[][] args() { return new Object[][]{ { MH_do_upcall, diff --git a/test/jdk/java/foreign/TestUpcallScope.java b/test/jdk/java/foreign/TestUpcallScope.java index 6b8930e1a55d..e7e8c8d9b7be 100644 --- a/test/jdk/java/foreign/TestUpcallScope.java +++ b/test/jdk/java/foreign/TestUpcallScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestUpcallScope */ @@ -35,7 +35,6 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemorySegment; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -43,13 +42,19 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallScope extends TestUpcallBase { static { System.loadLibrary("TestUpcall"); } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testUpcalls(int count, String fName, Ret ret, List paramTypes, List fields) throws Throwable { List> returnChecks = new ArrayList<>(); List> argChecks = new ArrayList<>(); diff --git a/test/jdk/java/foreign/TestUpcallStack.java b/test/jdk/java/foreign/TestUpcallStack.java index 4552cbef7349..324489b025d2 100644 --- a/test/jdk/java/foreign/TestUpcallStack.java +++ b/test/jdk/java/foreign/TestUpcallStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native/timeout=480 -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run junit/othervm/native/timeout=480 -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestUpcallStack */ @@ -36,7 +36,6 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemorySegment; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -44,13 +43,19 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallStack extends TestUpcallBase { static { System.loadLibrary("TestUpcallStack"); } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testUpcallsStack(int count, String fName, Ret ret, List paramTypes, List fields) throws Throwable { List> returnChecks = new ArrayList<>(); diff --git a/test/jdk/java/foreign/TestUpcallStress.java b/test/jdk/java/foreign/TestUpcallStress.java index db5320eff372..cc7c83c7f794 100644 --- a/test/jdk/java/foreign/TestUpcallStress.java +++ b/test/jdk/java/foreign/TestUpcallStress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * @bug 8337753 * - * @run testng/native/othervm + * @run junit/native/othervm * -Xcheck:jni * -XX:+IgnoreUnrecognizedVMOptions * -XX:-VerifyDependencies @@ -43,9 +43,6 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.MemorySegment; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; import jdk.test.lib.Utils; import java.lang.invoke.MethodHandle; @@ -55,6 +52,13 @@ import java.util.concurrent.*; import java.util.function.Consumer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUpcallStress extends TestUpcallBase { static { @@ -65,12 +69,12 @@ public class TestUpcallStress extends TestUpcallBase { ExecutorService executor; - @BeforeClass + @BeforeAll public void setup() { executor = Executors.newFixedThreadPool(THREAD_COUNT); } - @AfterClass + @AfterAll public void tearDown() throws InterruptedException { executor.shutdown(); // Let it run for a while, and then just terminate @@ -78,7 +82,8 @@ public void tearDown() throws InterruptedException { } - @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + @ParameterizedTest + @MethodSource("functions") public void testUpcallsStress(int count, String fName, Ret ret, List paramTypes, List fields) { for (int threadIdx = 0; threadIdx < THREAD_COUNT; threadIdx++) { diff --git a/test/jdk/java/foreign/TestUpcallStructScope.java b/test/jdk/java/foreign/TestUpcallStructScope.java index b71156d9e52f..6a6b35d12f3f 100644 --- a/test/jdk/java/foreign/TestUpcallStructScope.java +++ b/test/jdk/java/foreign/TestUpcallStructScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ /* * @test * - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * TestUpcallStructScope - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * TestUpcallStructScope @@ -37,7 +37,6 @@ import java.lang.foreign.*; -import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -46,9 +45,10 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class TestUpcallStructScope extends NativeTestHelper { static final MethodHandle MH_do_upcall; @@ -117,7 +117,7 @@ public void testOtherPointer() throws Throwable { // We've captured the address '42' from the upcall. This should have // the global scope, so it should still be alive here. MemorySegment captured = capturedSegment.get(); - assertEquals(argAddr, captured); + assertEquals(captured, argAddr); assertTrue(captured.scope().isAlive()); } } diff --git a/test/jdk/java/foreign/TestValueLayouts.java b/test/jdk/java/foreign/TestValueLayouts.java index 4c30a3c7d030..44dcc2a1f76a 100644 --- a/test/jdk/java/foreign/TestValueLayouts.java +++ b/test/jdk/java/foreign/TestValueLayouts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,17 +24,18 @@ /* * @test * @modules java.base/jdk.internal.misc - * @run testng TestValueLayouts + * @run junit TestValueLayouts */ -import org.testng.annotations.*; import java.lang.foreign.*; import java.nio.ByteOrder; import jdk.internal.misc.Unsafe; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestValueLayouts { @@ -141,10 +142,10 @@ void test(ValueLayout layout, Class carrier, long byteSize, long byteAlignment) { - assertEquals(layout.carrier(), carrier); - assertEquals(layout.byteSize(), byteSize); - assertEquals(layout.order(), ByteOrder.nativeOrder()); - assertEquals(layout.byteAlignment(), byteAlignment); + assertEquals(carrier, layout.carrier()); + assertEquals(byteSize, layout.byteSize()); + assertEquals(ByteOrder.nativeOrder(), layout.order()); + assertEquals(byteAlignment, layout.byteAlignment()); assertTrue(layout.name().isEmpty()); } diff --git a/test/jdk/java/foreign/TestVarArgs.java b/test/jdk/java/foreign/TestVarArgs.java index 006105da1a7c..14bc53748987 100644 --- a/test/jdk/java/foreign/TestVarArgs.java +++ b/test/jdk/java/foreign/TestVarArgs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 TestVarArgs + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 TestVarArgs */ import java.lang.foreign.Arena; @@ -35,8 +35,6 @@ import java.lang.foreign.ValueLayout; import java.lang.foreign.MemorySegment; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -48,6 +46,11 @@ import static java.lang.foreign.MemoryLayout.PathElement.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestVarArgs extends CallGeneratorHelper { static final MethodHandle MH_CHECK; @@ -65,7 +68,8 @@ public class TestVarArgs extends CallGeneratorHelper { static final MemorySegment VARARGS_ADDR = findNativeOrThrow("varargs"); - @Test(dataProvider = "variadicFunctions") + @ParameterizedTest + @MethodSource("variadicFunctions") public void testVarArgs(int count, String fName, Ret ret, // ignore this stuff List paramTypes, List fields) throws Throwable { try (Arena arena = Arena.ofConfined()) { @@ -121,7 +125,6 @@ private static List createFieldsForStruct(int fieldCount, Struc return fields; } - @DataProvider(name = "variadicFunctions") public static Object[][] variadicFunctions() { List downcalls = new ArrayList<>(); diff --git a/test/jdk/java/foreign/TestVarHandleCombinators.java b/test/jdk/java/foreign/TestVarHandleCombinators.java index ccf12b9fdee7..f7729f499db3 100644 --- a/test/jdk/java/foreign/TestVarHandleCombinators.java +++ b/test/jdk/java/foreign/TestVarHandleCombinators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,21 @@ /* * @test - * @run testng TestVarHandleCombinators + * @run junit TestVarHandleCombinators */ import java.lang.foreign.Arena; import java.lang.foreign.ValueLayout; -import org.testng.annotations.Test; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; public class TestVarHandleCombinators { @@ -47,17 +48,20 @@ public void testElementAccess() { byte[] arr = { 0, 0, -1, 0 }; MemorySegment segment = MemorySegment.ofArray(arr); - assertEquals((byte) vh.get(segment, 2), (byte) -1); + assertEquals((byte) -1, (byte) vh.get(segment, 2)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void testUnalignedElement() { VarHandle vh = ValueLayout.JAVA_BYTE.withByteAlignment(4).varHandle(); MemorySegment segment = MemorySegment.ofArray(new byte[4]); - vh.get(segment, 2L); //should throw + assertThrows(IllegalArgumentException.class, () -> { + vh.get(segment, 2L); + }); //FIXME: the VH only checks the alignment of the segment, which is fine if the VH is derived from layouts, //FIXME: but not if the VH is just created from scratch - we need a VH variable to govern this property, //FIXME: at least until the VM is fixed + } @Test @@ -67,7 +71,7 @@ public void testAlign() { Arena scope = Arena.ofAuto(); MemorySegment segment = scope.allocate(1L, 2); vh.set(segment, 0L, (byte) 10); // fine, memory region is aligned - assertEquals((byte) vh.get(segment, 0L), (byte) 10); + assertEquals((byte) 10, (byte) vh.get(segment, 0L)); } @Test @@ -76,8 +80,8 @@ public void testByteOrderLE() { byte[] arr = new byte[2]; MemorySegment segment = MemorySegment.ofArray(arr); vh.set(segment, 0L, (short) 0xFF); - assertEquals(arr[0], (byte) 0xFF); - assertEquals(arr[1], (byte) 0); + assertEquals((byte) 0xFF, arr[0]); + assertEquals((byte) 0, arr[1]); } @Test @@ -86,8 +90,8 @@ public void testByteOrderBE() { byte[] arr = new byte[2]; MemorySegment segment = MemorySegment.ofArray(arr); vh.set(segment, 0L, (short) 0xFF); - assertEquals(arr[0], (byte) 0); - assertEquals(arr[1], (byte) 0xFF); + assertEquals((byte) 0, arr[0]); + assertEquals((byte) 0xFF, arr[1]); } @Test @@ -104,9 +108,7 @@ public void testNestedSequenceAccess() { for (long i = 0; i < outer_size; i++) { for (long j = 0; j < inner_size; j++) { vh.set(segment, i * 40 + j * 8, count); - assertEquals( - (int)vh.get(segment.asSlice(i * inner_size * 8), j * 8), - count); + assertEquals( count, (int)vh.get(segment.asSlice(i * inner_size * 8), j * 8)); count++; } } diff --git a/test/jdk/java/foreign/UpcallTestHelper.java b/test/jdk/java/foreign/UpcallTestHelper.java index 8adf5580f514..bdf163507fe1 100644 --- a/test/jdk/java/foreign/UpcallTestHelper.java +++ b/test/jdk/java/foreign/UpcallTestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; public class UpcallTestHelper extends NativeTestHelper { diff --git a/test/jdk/java/foreign/arraystructs/TestArrayStructs.java b/test/jdk/java/foreign/arraystructs/TestArrayStructs.java index 6dba22becdd1..f411bdc5dcce 100644 --- a/test/jdk/java/foreign/arraystructs/TestArrayStructs.java +++ b/test/jdk/java/foreign/arraystructs/TestArrayStructs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @library ../ * @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK") * @modules java.base/jdk.internal.foreign - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=true * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=true @@ -38,15 +38,13 @@ * @library ../ * @requires (!(os.name == "Mac OS X" & os.arch == "aarch64") | jdk.foreign.linker != "FALLBACK") * @modules java.base/jdk.internal.foreign - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * -Djdk.internal.foreign.DowncallLinker.USE_SPEC=false * -Djdk.internal.foreign.UpcallLinker.USE_SPEC=false * TestArrayStructs */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -64,13 +62,19 @@ import static java.lang.foreign.MemoryLayout.sequenceLayout; import static java.lang.foreign.MemoryLayout.structLayout; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestArrayStructs extends NativeTestHelper { static { System.loadLibrary("ArrayStructs"); } // Test if structs of various different sizes, including non-powers of two, work correctly - @Test(dataProvider = "arrayStructs") + @ParameterizedTest + @MethodSource("arrayStructs") public void testArrayStruct(String functionName, FunctionDescriptor baseDesc, int numPrefixArgs, int numElements) throws Throwable { FunctionDescriptor downcallDesc = baseDesc.insertArgumentLayouts(0, C_POINTER); // CB MemoryLayout[] elementLayouts = Collections.nCopies(numElements, C_CHAR).toArray(MemoryLayout[]::new); @@ -109,7 +113,6 @@ public void testArrayStruct(String functionName, FunctionDescriptor baseDesc, in } } - @DataProvider public static Object[][] arrayStructs() { List cases = new ArrayList<>(); for (int i = 0; i < layouts.size(); i++) { diff --git a/test/jdk/java/foreign/callarranger/CallArrangerTestBase.java b/test/jdk/java/foreign/callarranger/CallArrangerTestBase.java index 037db225c65f..d37ebd32377f 100644 --- a/test/jdk/java/foreign/callarranger/CallArrangerTestBase.java +++ b/test/jdk/java/foreign/callarranger/CallArrangerTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,22 +27,22 @@ import java.util.Arrays; import java.util.List; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class CallArrangerTestBase { public static void checkArgumentBindings(CallingSequence callingSequence, Binding[][] argumentBindings) { - assertEquals(callingSequence.argumentBindingsCount(), argumentBindings.length, + assertEquals(argumentBindings.length, callingSequence.argumentBindingsCount(), callingSequence.asString() + " != " + Arrays.deepToString(argumentBindings)); for (int i = 0; i < callingSequence.argumentBindingsCount(); i++) { List actual = callingSequence.argumentBindings(i); Binding[] expected = argumentBindings[i]; - assertEquals(actual, Arrays.asList(expected), "bindings at: " + i + ": " + actual + " != " + Arrays.toString(expected)); + assertEquals(Arrays.asList(expected), actual, "bindings at: " + i + ": " + actual + " != " + Arrays.toString(expected)); } } public static void checkReturnBindings(CallingSequence callingSequence, Binding[] returnBindings) { - assertEquals(callingSequence.returnBindings(), Arrays.asList(returnBindings), callingSequence.returnBindings() + " != " + Arrays.toString(returnBindings)); + assertEquals(Arrays.asList(returnBindings), callingSequence.returnBindings(), callingSequence.returnBindings() + " != " + Arrays.toString(returnBindings)); } } diff --git a/test/jdk/java/foreign/callarranger/TestLayoutEquality.java b/test/jdk/java/foreign/callarranger/TestLayoutEquality.java index 0f4314894963..96ee11f6a96e 100644 --- a/test/jdk/java/foreign/callarranger/TestLayoutEquality.java +++ b/test/jdk/java/foreign/callarranger/TestLayoutEquality.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @compile platform/PlatformLayouts.java * @modules java.base/jdk.internal.foreign.abi * @modules java.base/jdk.internal.foreign.layout - * @run testng TestLayoutEquality + * @run junit TestLayoutEquality */ import java.lang.foreign.AddressLayout; @@ -35,18 +35,21 @@ import jdk.internal.foreign.layout.ValueLayouts; import platform.PlatformLayouts; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestLayoutEquality { - @Test(dataProvider = "layoutConstants") + @ParameterizedTest + @MethodSource("layoutConstants") public void testReconstructedEquality(ValueLayout layout) { ValueLayout newLayout = ValueLayouts.valueLayout(layout.carrier(), layout.order()); newLayout = newLayout.withByteAlignment(layout.byteAlignment()); @@ -55,15 +58,14 @@ public void testReconstructedEquality(ValueLayout layout) { } // properties should be equal - assertEquals(newLayout.byteSize(), layout.byteSize()); - assertEquals(newLayout.byteAlignment(), layout.byteAlignment()); - assertEquals(newLayout.name(), layout.name()); + assertEquals(layout.byteSize(), newLayout.byteSize()); + assertEquals(layout.byteAlignment(), newLayout.byteAlignment()); + assertEquals(layout.name(), newLayout.name()); // layouts should be equals - assertEquals(newLayout, layout); + assertEquals(layout, newLayout); } - @DataProvider public static Object[][] layoutConstants() throws ReflectiveOperationException { List testValues = new ArrayList<>(); diff --git a/test/jdk/java/foreign/callarranger/TestLinuxAArch64CallArranger.java b/test/jdk/java/foreign/callarranger/TestLinuxAArch64CallArranger.java index ae08f1c9be43..ca0e25eedf24 100644 --- a/test/jdk/java/foreign/callarranger/TestLinuxAArch64CallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestLinuxAArch64CallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * java.base/jdk.internal.foreign.abi * java.base/jdk.internal.foreign.abi.aarch64 * @build CallArrangerTestBase - * @run testng TestLinuxAArch64CallArranger + * @run junit TestLinuxAArch64CallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -43,8 +43,6 @@ import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.aarch64.CallArranger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodType; @@ -55,10 +53,15 @@ import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; import static platform.PlatformLayouts.AArch64.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestLinuxAArch64CallArranger extends CallArrangerTestBase { private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); @@ -72,8 +75,8 @@ public void testEmpty() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) } @@ -96,8 +99,8 @@ public void testInteger() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -126,8 +129,8 @@ public void testTwoIntTwoFloat() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -140,7 +143,8 @@ public void testTwoIntTwoFloat() { checkReturnBindings(callingSequence, new Binding[]{}); } - @Test(dataProvider = "structs") + @ParameterizedTest + @MethodSource("structs") public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { MethodType mt = MethodType.methodType(void.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); @@ -148,8 +152,8 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -159,7 +163,6 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { checkReturnBindings(callingSequence, new Binding[]{}); } - @DataProvider public static Object[][] structs() { MemoryLayout struct2 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT); return new Object[][]{ @@ -208,8 +211,8 @@ public void testMultipleStructs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -239,8 +242,8 @@ public void testReturnStruct1() { assertTrue(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER)); + assertEquals(MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(FunctionDescriptor.ofVoid(ADDRESS, C_POINTER), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -263,8 +266,8 @@ public void testReturnStruct2() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, @@ -292,8 +295,8 @@ public void testStructHFA1() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, @@ -330,8 +333,8 @@ public void testStructHFA3() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -384,8 +387,8 @@ public void testStructStackSpill() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -413,8 +416,8 @@ public void testVarArgsInRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); // This is identical to the non-variadic calling sequence checkArgumentBindings(callingSequence, new Binding[][]{ @@ -440,8 +443,8 @@ public void testFloatArrayStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); // This is identical to the non-variadic calling sequence checkArgumentBindings(callingSequence, new Binding[][]{ diff --git a/test/jdk/java/foreign/callarranger/TestMacOsAArch64CallArranger.java b/test/jdk/java/foreign/callarranger/TestMacOsAArch64CallArranger.java index 30119db72e8c..b8217f913399 100644 --- a/test/jdk/java/foreign/callarranger/TestMacOsAArch64CallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestMacOsAArch64CallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * java.base/jdk.internal.foreign.abi * java.base/jdk.internal.foreign.abi.aarch64 * @build CallArrangerTestBase - * @run testng TestMacOsAArch64CallArranger + * @run junit TestMacOsAArch64CallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -43,8 +43,6 @@ import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.aarch64.CallArranger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodType; @@ -54,9 +52,11 @@ import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*; import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; import static platform.PlatformLayouts.AArch64.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class TestMacOsAArch64CallArranger extends CallArrangerTestBase { @@ -71,8 +71,8 @@ public void testVarArgsOnStack() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); // The two variadic arguments should be allocated on the stack checkArgumentBindings(callingSequence, new Binding[][]{ @@ -99,8 +99,8 @@ public void testMacArgsOnStack() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -143,8 +143,8 @@ public void testMacArgsOnStack2() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -199,8 +199,8 @@ public void testMacArgsOnStack3() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -252,8 +252,8 @@ public void testMacArgsOnStack4() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -304,8 +304,8 @@ public void testMacArgsOnStack5() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -358,8 +358,8 @@ public void testMacArgsOnStack6() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, diff --git a/test/jdk/java/foreign/callarranger/TestRISCV64CallArranger.java b/test/jdk/java/foreign/callarranger/TestRISCV64CallArranger.java index f24862396459..7bd673aff278 100644 --- a/test/jdk/java/foreign/callarranger/TestRISCV64CallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestRISCV64CallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023, Institute of Software, Chinese Academy of Sciences. * All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -33,7 +33,7 @@ * java.base/jdk.internal.foreign.abi.riscv64 * java.base/jdk.internal.foreign.abi.riscv64.linux * @build CallArrangerTestBase - * @run testng TestRISCV64CallArranger + * @run junit TestRISCV64CallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -45,8 +45,6 @@ import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64CallArranger; import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodType; @@ -58,10 +56,15 @@ import static jdk.internal.foreign.abi.riscv64.RISCV64Architecture.Regs.*; import static platform.PlatformLayouts.RISCV64.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestRISCV64CallArranger extends CallArrangerTestBase { private static final short STACK_SLOT_SIZE = 8; @@ -76,8 +79,8 @@ public void testEmpty() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) } @@ -100,8 +103,8 @@ public void testInteger() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -128,8 +131,8 @@ public void testTwoIntTwoFloat() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -142,7 +145,8 @@ public void testTwoIntTwoFloat() { checkReturnBindings(callingSequence, new Binding[]{}); } - @Test(dataProvider = "structs") + @ParameterizedTest + @MethodSource("structs") public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { MethodType mt = MethodType.methodType(void.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); @@ -150,8 +154,8 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -161,7 +165,6 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { checkReturnBindings(callingSequence, new Binding[]{}); } - @DataProvider public static Object[][] structs() { MemoryLayout struct1 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT); return new Object[][]{ @@ -226,8 +229,8 @@ public void testStructFA1() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, @@ -264,8 +267,8 @@ public void testStructFA2() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, @@ -305,8 +308,8 @@ void spillFloatingPointStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -336,8 +339,8 @@ public void testStructBoth() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -384,8 +387,8 @@ public void testStructStackSpill() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -413,8 +416,8 @@ public void testVarArgsInRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); // This is identical to the non-variadic calling sequence checkArgumentBindings(callingSequence, new Binding[][]{ @@ -442,8 +445,8 @@ public void testVarArgsLong() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); // This is identical to the non-variadic calling sequence checkArgumentBindings(callingSequence, new Binding[][]{ @@ -474,11 +477,9 @@ public void testReturnStruct1() { assertTrue(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), - MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, - int.class, int.class, float.class)); - assertEquals(callingSequence.functionDesc(), - FunctionDescriptor.ofVoid(ADDRESS, C_POINTER, C_INT, C_INT, C_FLOAT)); + assertEquals( MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, + int.class, int.class, float.class), callingSequence.callerMethodType()); + assertEquals( FunctionDescriptor.ofVoid(ADDRESS, C_POINTER, C_INT, C_INT, C_FLOAT), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -501,8 +502,8 @@ public void testReturnStruct2() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, diff --git a/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java b/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java index 53317b22dc08..8f911242d22f 100644 --- a/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestSysVCallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * java.base/jdk.internal.foreign.abi.x64 * java.base/jdk.internal.foreign.abi.x64.sysv * @build CallArrangerTestBase - * @run testng TestSysVCallArranger + * @run junit TestSysVCallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -41,8 +41,6 @@ import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.x64.sysv.CallArranger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodType; @@ -52,10 +50,15 @@ import static jdk.internal.foreign.abi.x64.X86_64Architecture.Regs.*; import static platform.PlatformLayouts.SysV.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSysVCallArranger extends CallArrangerTestBase { private static final short STACK_SLOT_SIZE = 8; @@ -70,8 +73,8 @@ public void testEmpty() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -79,7 +82,7 @@ public void testEmpty() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -97,8 +100,8 @@ public void testNestedStructs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -108,7 +111,7 @@ public void testNestedStructs() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -127,8 +130,8 @@ public void testNestedUnion() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -138,7 +141,7 @@ public void testNestedUnion() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -151,8 +154,8 @@ public void testIntegerRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -166,7 +169,7 @@ public void testIntegerRegs() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -181,8 +184,8 @@ public void testDoubleRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -198,7 +201,7 @@ public void testDoubleRegs() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 8); + assertEquals(8, bindings.nVectorArgs()); } @Test @@ -215,8 +218,8 @@ public void testMixed() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -242,7 +245,7 @@ public void testMixed() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 8); + assertEquals(8, bindings.nVectorArgs()); } /** @@ -271,8 +274,8 @@ public void testAbiExample() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -294,7 +297,7 @@ public void testAbiExample() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 3); + assertEquals(3, bindings.nVectorArgs()); } /** @@ -313,8 +316,8 @@ public void testMemoryAddress() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -323,10 +326,11 @@ public void testMemoryAddress() { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } - @Test(dataProvider = "structs") + @ParameterizedTest + @MethodSource("structs") public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { MethodType mt = MethodType.methodType(void.class, MemorySegment.class); FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); @@ -334,8 +338,8 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -344,11 +348,10 @@ public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { checkReturnBindings(callingSequence, new Binding[]{}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } - @DataProvider public static Object[][] structs() { return new Object[][]{ { MemoryLayout.structLayout(C_LONG), new Binding[]{ @@ -392,8 +395,8 @@ public void testReturnRegisterStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, @@ -410,7 +413,7 @@ public void testReturnRegisterStruct() { bufferStore(8, long.class) }); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -423,8 +426,8 @@ public void testIMR() { assertTrue(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER)); + assertEquals(MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(FunctionDescriptor.ofVoid(ADDRESS, C_POINTER), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -433,7 +436,7 @@ public void testIMR() { checkReturnBindings(callingSequence, new Binding[] {}); - assertEquals(bindings.nVectorArgs(), 0); + assertEquals(0, bindings.nVectorArgs()); } @Test @@ -446,8 +449,8 @@ public void testFloatStructsUpcall() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.calleeMethodType(), mt); - assertEquals(callingSequence.functionDesc(), fd); + assertEquals(mt, callingSequence.calleeMethodType()); + assertEquals(fd, callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { allocate(struct), dup(), vmLoad(xmm0, float.class), bufferStore(0, float.class) }, @@ -457,7 +460,7 @@ public void testFloatStructsUpcall() { bufferLoad(0, float.class), vmStore(xmm0, float.class) }); - assertEquals(bindings.nVectorArgs(), 1); + assertEquals(1, bindings.nVectorArgs()); } } diff --git a/test/jdk/java/foreign/callarranger/TestWindowsAArch64CallArranger.java b/test/jdk/java/foreign/callarranger/TestWindowsAArch64CallArranger.java index 4c612ef868c6..c799e90d6ccc 100644 --- a/test/jdk/java/foreign/callarranger/TestWindowsAArch64CallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestWindowsAArch64CallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * java.base/jdk.internal.foreign.abi * java.base/jdk.internal.foreign.abi.aarch64 * @build CallArrangerTestBase - * @run testng TestWindowsAArch64CallArranger + * @run junit TestWindowsAArch64CallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -41,8 +41,6 @@ import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.aarch64.CallArranger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.invoke.MethodType; @@ -52,9 +50,11 @@ import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*; import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; import static platform.PlatformLayouts.AArch64.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class TestWindowsAArch64CallArranger extends CallArrangerTestBase { @@ -69,8 +69,8 @@ public void testWindowsArgsInRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -92,8 +92,8 @@ public void testWindowsVarArgsInRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -118,8 +118,8 @@ public void testWindowsArgsInRegsAndOnStack() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -152,8 +152,8 @@ public void testWindowsVarArgsInRegsAndOnStack() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -182,8 +182,8 @@ public void testWindowsHfa4FloatsInFloatRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -216,8 +216,8 @@ public void testWindowsVariadicHfa4FloatsInIntRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -245,8 +245,8 @@ public void testWindowsHfa2DoublesInFloatRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -274,8 +274,8 @@ public void testWindowsVariadicHfa2DoublesInIntRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -303,8 +303,8 @@ public void testWindowsHfa3DoublesInFloatRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -335,8 +335,8 @@ public void testWindowsVariadicHfa3DoublesAsReferenceStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, diff --git a/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java b/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java index 3f47952dd83e..25fc025f047e 100644 --- a/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java +++ b/test/jdk/java/foreign/callarranger/TestWindowsCallArranger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * java.base/jdk.internal.foreign.abi.x64 * java.base/jdk.internal.foreign.abi.x64.windows * @build CallArrangerTestBase - * @run testng TestWindowsCallArranger + * @run junit TestWindowsCallArranger */ import java.lang.foreign.FunctionDescriptor; @@ -43,7 +43,6 @@ import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.x64.windows.CallArranger; -import org.testng.annotations.Test; import java.lang.invoke.MethodType; @@ -55,7 +54,8 @@ import static jdk.internal.foreign.abi.x64.X86_64Architecture.Regs.*; import static platform.PlatformLayouts.Win64.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class TestWindowsCallArranger extends CallArrangerTestBase { @@ -70,8 +70,8 @@ public void testEmpty() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) } @@ -87,8 +87,8 @@ public void testIntegerRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -109,8 +109,8 @@ public void testDoubleRegs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -133,8 +133,8 @@ public void testMixed() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -164,8 +164,8 @@ public void testAbiExample() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -201,8 +201,8 @@ public void testAbiExampleVarargs() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fdExpected); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fdExpected, callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -235,8 +235,8 @@ public void testStructRegister() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -265,8 +265,8 @@ public void testStructReference() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -296,8 +296,8 @@ public void testMemoryAddress() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -317,8 +317,8 @@ public void testReturnRegisterStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -341,8 +341,8 @@ public void testIMR() { assertTrue(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER)); + assertEquals(MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(FunctionDescriptor.ofVoid(ADDRESS, C_POINTER), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, @@ -370,8 +370,8 @@ public void testStackStruct() { assertFalse(bindings.isInMemoryReturn()); CallingSequence callingSequence = bindings.callingSequence(); - assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); - assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); + assertEquals(mt.insertParameterTypes(0, MemorySegment.class), callingSequence.callerMethodType()); + assertEquals(fd.insertArgumentLayouts(0, ADDRESS), callingSequence.functionDesc()); checkArgumentBindings(callingSequence, new Binding[][]{ { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, diff --git a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java index 8ef5483bd82a..f88dd051841c 100644 --- a/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java +++ b/test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java @@ -25,11 +25,9 @@ * @test * @bug 8356126 * @library ../ /test/lib - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestCaptureCallState + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestCaptureCallState */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -48,8 +46,14 @@ import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_LONG; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCaptureCallState extends NativeTestHelper { static { @@ -67,7 +71,7 @@ public void testApiContracts() { assertThrows(IllegalArgumentException.class, () -> Linker.Option.captureCallState("Does not exist")); var duplicateOpt = Linker.Option.captureCallState("errno", "errno"); // duplicates var noDuplicateOpt = Linker.Option.captureCallState("errno"); - assertEquals(duplicateOpt, noDuplicateOpt, "auto deduplication"); + assertEquals(noDuplicateOpt, duplicateOpt, "auto deduplication"); var display = duplicateOpt.toString(); assertTrue(display.contains("errno"), "toString should contain state name 'errno': " + display); } @@ -75,7 +79,8 @@ public void testApiContracts() { private record SaveValuesCase(String nativeTarget, FunctionDescriptor nativeDesc, String threadLocalName, Consumer resultCheck, boolean expectTestValue, boolean critical) {} - @Test(dataProvider = "cases") + @ParameterizedTest + @MethodSource("cases") public void testSavedThreadLocal(SaveValuesCase testCase) throws Throwable { List options = new ArrayList<>(); options.add(Linker.Option.captureCallState(testCase.threadLocalName())); @@ -101,14 +106,15 @@ public void testSavedThreadLocal(SaveValuesCase testCase) throws Throwable { testCase.resultCheck().accept(result); int savedErrno = (int) errnoHandle.get(saveSeg, 0L); if (testCase.expectTestValue()) { - assertEquals(savedErrno, testValue); + assertEquals(testValue, savedErrno); } else { - assertEquals(savedErrno, prevValue); + assertEquals(prevValue, savedErrno); } } } - @Test(dataProvider = "invalidCaptureSegmentCases") + @ParameterizedTest + @MethodSource("invalidCaptureSegmentCases") public void testInvalidCaptureSegment(MemorySegment captureSegment, Class expectedExceptionType, String expectedExceptionMessage, Linker.Option[] extraOptions) { @@ -128,7 +134,6 @@ public void testInvalidCaptureSegment(MemorySegment captureSegment, } } - @DataProvider public static Object[][] cases() { List cases = new ArrayList<>(); @@ -138,9 +143,9 @@ public static Object[][] cases() { cases.add(new SaveValuesCase("noset_errno_V", FunctionDescriptor.ofVoid(JAVA_INT), "errno", o -> {}, false, critical)); cases.add(new SaveValuesCase("set_errno_I", FunctionDescriptor.of(JAVA_INT, JAVA_INT), - "errno", o -> assertEquals((int) o, 42), true, critical)); + "errno", o -> assertEquals(42, (int) o), true, critical)); cases.add(new SaveValuesCase("set_errno_D", FunctionDescriptor.of(JAVA_DOUBLE, JAVA_INT), - "errno", o -> assertEquals((double) o, 42.0), true, critical)); + "errno", o -> assertEquals(42.0, (double) o), true, critical)); cases.add(structCase("SL", Map.of(JAVA_LONG.withName("x"), 42L), true, critical)); cases.add(structCase("SLL", Map.of(JAVA_LONG.withName("x"), 42L, @@ -180,14 +185,13 @@ static SaveValuesCase structCase(String name, MemoryLayout fieldLayout = field.getKey(); VarHandle fieldHandle = layout.varHandle(MemoryLayout.PathElement.groupElement(fieldLayout.name().get())); Object value = field.getValue(); - check = check.andThen(o -> assertEquals(fieldHandle.get(o, 0L), value)); + check = check.andThen(o -> assertEquals(value, fieldHandle.get(o, 0L))); } String prefix = expectTestValue ? "set_errno_" : "noset_errno_"; return new SaveValuesCase(prefix + name, FunctionDescriptor.of(layout, JAVA_INT), "errno", check, expectTestValue, critical); } - @DataProvider public static Object[][] invalidCaptureSegmentCases() { return new Object[][]{ {Arena.ofAuto().allocate(1), IndexOutOfBoundsException.class, ".*Out of bound access on segment.*", new Linker.Option[0]}, diff --git a/test/jdk/java/foreign/channels/AbstractChannelsTest.java b/test/jdk/java/foreign/channels/AbstractChannelsTest.java index 6c9e64a40a27..b22342cb067f 100644 --- a/test/jdk/java/foreign/channels/AbstractChannelsTest.java +++ b/test/jdk/java/foreign/channels/AbstractChannelsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,14 +32,16 @@ import java.util.stream.Stream; import jdk.test.lib.RandomFactory; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; /** * Not a test, but infra for channel tests. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class AbstractChannelsTest { static final Class IOE = IOException.class; @@ -120,28 +122,24 @@ static void assertCauses(Throwable ex, Class... exceptions) } } - @DataProvider(name = "confinedArenas") public static Object[][] confinedArenas() { return new Object[][] { { ArenaSupplier.NEW_CONFINED }, }; } - @DataProvider(name = "sharedArenas") public static Object[][] sharedArenas() { return new Object[][] { { ArenaSupplier.NEW_SHARED }, }; } - @DataProvider(name = "closeableArenas") public static Object[][] closeableArenas() { return Stream.of(sharedArenas(), confinedArenas()) .flatMap(Arrays::stream) .toArray(Object[][]::new); } - @DataProvider(name = "sharedArenasAndTimeouts") public static Object[][] sharedArenasAndTimeouts() { return new Object[][] { { ArenaSupplier.NEW_SHARED , 0 }, diff --git a/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java b/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java index 37fef8bb4b66..9f315f10d75f 100644 --- a/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java +++ b/test/jdk/java/foreign/channels/TestAsyncSocketChannels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,9 @@ * @library /test/lib * @modules java.base/sun.nio.ch * @key randomness - * @run testng/othervm TestAsyncSocketChannels - * @run testng/othervm -Dsun.nio.ch.disableSynchronousRead=true TestAsyncSocketChannels - * @run testng/othervm -Dsun.nio.ch.disableSynchronousRead=false TestAsyncSocketChannels + * @run junit/othervm TestAsyncSocketChannels + * @run junit/othervm -Dsun.nio.ch.disableSynchronousRead=true TestAsyncSocketChannels + * @run junit/othervm -Dsun.nio.ch.disableSynchronousRead=false TestAsyncSocketChannels */ import java.io.IOException; @@ -50,15 +50,19 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; -import org.testng.annotations.*; import static java.lang.System.out; import static java.util.concurrent.TimeUnit.SECONDS; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests consisting of buffer views with asynchronous NIO network channels. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestAsyncSocketChannels extends AbstractChannelsTest { static final Class IOE = IOException.class; @@ -67,7 +71,8 @@ public class TestAsyncSocketChannels extends AbstractChannelsTest { static final Class ISE = IllegalStateException.class; /** Tests that confined sessions are not supported. */ - @Test(dataProvider = "confinedArenas") + @ParameterizedTest + @MethodSource("confinedArenas") public void testWithConfined(Supplier arenaSupplier) throws Throwable { @@ -92,13 +97,14 @@ public void testWithConfined(Supplier arenaSupplier) for (var ioOp : ioOps) { out.println("testAsyncWithConfined - op"); var handler = new TestHandler(); - expectThrows(IAE, () -> ioOp.accept(handler)); + assertThrows(IAE, () -> ioOp.accept(handler)); } } } /** Tests that I/O with a closed session throws a suitable exception. */ - @Test(dataProvider = "sharedArenasAndTimeouts") + @ParameterizedTest + @MethodSource("sharedArenasAndTimeouts") public void testIOWithClosedSharedSession(Supplier arenaSupplier, int timeout) throws Exception { @@ -110,7 +116,7 @@ public void testIOWithClosedSharedSession(Supplier arenaSupplier, int tim ByteBuffer[] buffers = segmentBuffersOfSize(8, drop, 32); drop.close(); { - assertCauses(expectThrows(EE, () -> connectedChannel.read(bb).get()), IOE, ISE); + assertCauses(assertThrows(EE, () -> connectedChannel.read(bb).get()), IOE, ISE); } { var handler = new TestHandler(); @@ -128,7 +134,7 @@ public void testIOWithClosedSharedSession(Supplier arenaSupplier, int tim handler.await().assertFailedWith(ISE).assertExceptionMessage("Already closed"); } { - assertCauses(expectThrows(EE, () -> connectedChannel.write(bb).get()), IOE, ISE); + assertCauses(assertThrows(EE, () -> connectedChannel.write(bb).get()), IOE, ISE); } { var handler = new TestHandler(); @@ -149,7 +155,8 @@ public void testIOWithClosedSharedSession(Supplier arenaSupplier, int tim } /** Tests basic I/O operations work with views over implicit and shared sessions. */ - @Test(dataProvider = "sharedArenas") + @ParameterizedTest + @MethodSource("sharedArenas") public void testBasicIOWithSupportedSession(Supplier arenaSupplier) throws Exception { @@ -168,9 +175,9 @@ public void testBasicIOWithSupportedSession(Supplier arenaSupplier) { // Future variants ByteBuffer bb1 = segment1.asByteBuffer(); ByteBuffer bb2 = segment2.asByteBuffer(); - assertEquals((int)asc1.write(bb1).get(), 10); - assertEquals((int)asc2.read(bb2).get(), 10); - assertEquals(bb2.flip(), ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + assertEquals(10, (int)asc1.write(bb1).get()); + assertEquals(10, (int)asc2.read(bb2).get()); + assertEquals(ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), bb2.flip()); } { // CompletionHandler variants ByteBuffer bb1 = segment1.asByteBuffer(); @@ -181,7 +188,7 @@ public void testBasicIOWithSupportedSession(Supplier arenaSupplier) var readHandler = new TestHandler(); asc2.read(new ByteBuffer[]{bb2}, 0, 1, 30L, SECONDS, null, readHandler); readHandler.await().assertCompleteWith(10L); - assertEquals(bb2.flip(), ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + assertEquals(ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), bb2.flip()); } { // Gathering/Scattering variants var writeBuffers = mixedBuffersOfSize(16, drop, 32); @@ -193,13 +200,14 @@ public void testBasicIOWithSupportedSession(Supplier arenaSupplier) var readHandler = new TestHandler(); asc2.read(readBuffers, 0, 16, 30L, SECONDS, null, readHandler); readHandler.await().assertCompleteWith(expectedCount); - assertEquals(flip(readBuffers), clear(writeBuffers)); + assertArrayEquals(clear(writeBuffers), flip(readBuffers)); } } } /** Tests that a session is not closeable when there is an outstanding read operation. */ - @Test(dataProvider = "sharedArenasAndTimeouts") + @ParameterizedTest + @MethodSource("sharedArenasAndTimeouts") public void testCloseWithOutstandingRead(Supplier arenaSupplier, int timeout) throws Throwable { @@ -235,7 +243,8 @@ public void testCloseWithOutstandingRead(Supplier arenaSupplier, int time /** Tests that a session is not closeable when there is an outstanding write operation. */ // Note: limited scenarios are checked, given the 5 sec sleep! - @Test(dataProvider = "sharedArenasAndTimeouts") + @ParameterizedTest + @MethodSource("sharedArenasAndTimeouts") public void testCloseWithOutstandingWrite(Supplier arenaSupplier, int timeout) throws Throwable { @@ -357,20 +366,20 @@ TestHandler await() throws InterruptedException{ } TestHandler assertCompleteWith(V value) { - assertEquals(result.longValue(), value.longValue()); - assertEquals(throwable, null); + assertEquals(value.longValue(), result.longValue()); + assertEquals(null, throwable); return this; } TestHandler assertFailedWith(Class expectedException) { assertTrue(expectedException.isInstance(throwable), "Expected type:%s, got:%s".formatted(expectedException, throwable) ); - assertEquals(result, null, "Unexpected result: " + result); + assertEquals(null, result, "Unexpected result: " + result); return this; } TestHandler assertExceptionMessage(String expectedMessage) { - assertEquals(throwable.getMessage(), expectedMessage); + assertEquals(expectedMessage, throwable.getMessage()); return this; } diff --git a/test/jdk/java/foreign/channels/TestSocketChannels.java b/test/jdk/java/foreign/channels/TestSocketChannels.java index e2cb012a5088..77bc79c34084 100644 --- a/test/jdk/java/foreign/channels/TestSocketChannels.java +++ b/test/jdk/java/foreign/channels/TestSocketChannels.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @library /test/lib * @modules java.base/sun.nio.ch * @key randomness - * @run testng/othervm TestSocketChannels + * @run junit/othervm TestSocketChannels */ import java.lang.foreign.Arena; @@ -43,20 +43,27 @@ import java.lang.foreign.MemorySegment; -import org.testng.annotations.*; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests consisting of buffer views with synchronous NIO network channels. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSocketChannels extends AbstractChannelsTest { static final Class ISE = IllegalStateException.class; static final Class WTE = WrongThreadException.class; - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testBasicIOWithClosedSegment(Supplier arenaSupplier) throws Exception { @@ -66,16 +73,17 @@ public void testBasicIOWithClosedSegment(Supplier arenaSupplier) Arena drop = arenaSupplier.get(); ByteBuffer bb = segmentBufferOfSize(drop, 16); drop.close(); - assertMessage(expectThrows(ISE, () -> channel.read(bb)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.read(new ByteBuffer[] {bb})), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}, 0, 1)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.write(bb)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.write(new ByteBuffer[] {bb})), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}, 0 ,1)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.read(bb)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb})), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}, 0, 1)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.write(bb)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb})), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}, 0 ,1)), "Already closed"); } } - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testScatterGatherWithClosedSegment(Supplier arenaSupplier) throws Exception { @@ -85,14 +93,15 @@ public void testScatterGatherWithClosedSegment(Supplier arenaSupplier) Arena drop = arenaSupplier.get(); ByteBuffer[] buffers = segmentBuffersOfSize(8, drop, 16); drop.close(); - assertMessage(expectThrows(ISE, () -> channel.write(buffers)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.read(buffers)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.write(buffers, 0 ,8)), "Already closed"); - assertMessage(expectThrows(ISE, () -> channel.read(buffers, 0, 8)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.write(buffers)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.read(buffers)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.write(buffers, 0 ,8)), "Already closed"); + assertMessage(assertThrows(ISE, () -> channel.read(buffers, 0, 8)), "Already closed"); } } - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testBasicIO(Supplier arenaSupplier) throws Exception { @@ -110,9 +119,9 @@ public void testBasicIO(Supplier arenaSupplier) } ByteBuffer bb1 = segment1.asByteBuffer(); ByteBuffer bb2 = segment2.asByteBuffer(); - assertEquals(sc1.write(bb1), 10); - assertEquals(sc2.read(bb2), 10); - assertEquals(bb2.flip(), ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + assertEquals(10, sc1.write(bb1)); + assertEquals(10, sc2.read(bb2)); + assertEquals(ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), bb2.flip()); } } @@ -128,13 +137,14 @@ public void testBasicHeapIOWithGlobalSession() throws Exception { } ByteBuffer bb1 = segment1.asByteBuffer(); ByteBuffer bb2 = segment2.asByteBuffer(); - assertEquals(sc1.write(bb1), 10); - assertEquals(sc2.read(bb2), 10); - assertEquals(bb2.flip(), ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + assertEquals(10, sc1.write(bb1)); + assertEquals(10, sc2.read(bb2)); + assertEquals(ByteBuffer.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), bb2.flip()); } } - @Test(dataProvider = "confinedArenas") + @ParameterizedTest + @MethodSource("confinedArenas") public void testIOOnConfinedFromAnotherThread(Supplier arenaSupplier) throws Exception { @@ -145,7 +155,7 @@ public void testIOOnConfinedFromAnotherThread(Supplier arenaSupplier) Arena scope = drop; var segment = scope.allocate(10, 1); ByteBuffer bb = segment.asByteBuffer(); - List ioOps = List.of( + List ioOps = List.of( () -> channel.write(bb), () -> channel.read(bb), () -> channel.write(new ByteBuffer[] {bb}), @@ -155,7 +165,7 @@ public void testIOOnConfinedFromAnotherThread(Supplier arenaSupplier) ); for (var ioOp : ioOps) { AtomicReference exception = new AtomicReference<>(); - Runnable task = () -> exception.set(expectThrows(WTE, ioOp)); + Runnable task = () -> exception.set(assertThrows(WTE, ioOp)); var t = new Thread(task); t.start(); t.join(); @@ -164,7 +174,8 @@ public void testIOOnConfinedFromAnotherThread(Supplier arenaSupplier) } } - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testScatterGatherIO(Supplier arenaSupplier) throws Exception { @@ -176,13 +187,14 @@ public void testScatterGatherIO(Supplier arenaSupplier) var writeBuffers = mixedBuffersOfSize(32, drop, 64); var readBuffers = mixedBuffersOfSize(32, drop, 64); long expectedCount = remaining(writeBuffers); - assertEquals(writeNBytes(sc1, writeBuffers, 0, 32, expectedCount), expectedCount); - assertEquals(readNBytes(sc2, readBuffers, 0, 32, expectedCount), expectedCount); - assertEquals(flip(readBuffers), clear(writeBuffers)); + assertEquals(expectedCount, writeNBytes(sc1, writeBuffers, 0, 32, expectedCount)); + assertEquals(expectedCount, readNBytes(sc2, readBuffers, 0, 32, expectedCount)); + assertArrayEquals(clear(writeBuffers), flip(readBuffers)); } } - @Test(dataProvider = "closeableArenas") + @ParameterizedTest + @MethodSource("closeableArenas") public void testBasicIOWithDifferentSessions(Supplier arenaSupplier) throws Exception { @@ -199,9 +211,9 @@ public void testBasicIOWithDifferentSessions(Supplier arenaSupplier) .toArray(ByteBuffer[]::new); long expectedCount = remaining(writeBuffers); - assertEquals(writeNBytes(sc1, writeBuffers, 0, 32, expectedCount), expectedCount); - assertEquals(readNBytes(sc2, readBuffers, 0, 32, expectedCount), expectedCount); - assertEquals(flip(readBuffers), clear(writeBuffers)); + assertEquals(expectedCount, writeNBytes(sc1, writeBuffers, 0, 32, expectedCount)); + assertEquals(expectedCount, readNBytes(sc2, readBuffers, 0, 32, expectedCount)); + assertArrayEquals(clear(writeBuffers), flip(readBuffers)); } } diff --git a/test/jdk/java/foreign/critical/TestCritical.java b/test/jdk/java/foreign/critical/TestCritical.java index 499278685cf6..4c09b302058f 100644 --- a/test/jdk/java/foreign/critical/TestCritical.java +++ b/test/jdk/java/foreign/critical/TestCritical.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,9 @@ * @test * @library ../ /test/lib * - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestCritical + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestCritical */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -48,8 +46,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCritical extends NativeTestHelper { static final MemoryLayout CAPTURE_STATE_LAYOUT = Linker.Option.captureStateLayout(); @@ -69,7 +72,7 @@ public void testEmpty() throws Throwable { public void testIdentity() throws Throwable { MethodHandle handle = downcallHandle("identity", FunctionDescriptor.of(C_INT, C_INT), Linker.Option.critical(false)); int result = (int) handle.invokeExact(42); - assertEquals(result, 42); + assertEquals(42, result); } @Test @@ -84,16 +87,17 @@ public void testWithReturnBuffer() throws Throwable { try (Arena arena = Arena.ofConfined()) { MemorySegment result = (MemorySegment) handle.invokeExact((SegmentAllocator) arena); long x = (long) vhX.get(result, 0L); - assertEquals(x, 10); + assertEquals(10, x); long y = (long) vhY.get(result, 0L); - assertEquals(y, 11); + assertEquals(11, y); } } public record AllowHeapCase(IntFunction newArraySegment, ValueLayout elementLayout, String fName, FunctionDescriptor fDesc, boolean readOnly, boolean captureErrno) {} - @Test(dataProvider = "allowHeapCases") + @ParameterizedTest + @MethodSource("allowHeapCases") public void testAllowHeap(AllowHeapCase testCase) throws Throwable { List options = new ArrayList<>(); options.add(Linker.Option.critical(true)); @@ -138,12 +142,11 @@ public void testAllowHeap(AllowHeapCase testCase) throws Throwable { if (testCase.captureErrno()) { int errno = (int) ERRNO_HANDLE.get(captureSegment, 0L); - assertEquals(errno, 42); + assertEquals(42, errno); } } } - @DataProvider public Object[][] allowHeapCases() { FunctionDescriptor voidDesc = FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_INT); FunctionDescriptor intDesc = voidDesc.changeReturnLayout(C_INT).insertArgumentLayouts(0, C_INT); diff --git a/test/jdk/java/foreign/critical/TestCriticalUpcall.java b/test/jdk/java/foreign/critical/TestCriticalUpcall.java index d6fd640539e7..c4f59bc5ac10 100644 --- a/test/jdk/java/foreign/critical/TestCriticalUpcall.java +++ b/test/jdk/java/foreign/critical/TestCriticalUpcall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,9 @@ * @test * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestCriticalUpcall + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestCriticalUpcall */ -import org.testng.annotations.Test; import java.io.IOException; import java.lang.foreign.FunctionDescriptor; @@ -37,7 +36,8 @@ import java.lang.invoke.MethodHandle; import java.util.List; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; public class TestCriticalUpcall extends UpcallTestHelper { diff --git a/test/jdk/java/foreign/dontrelease/TestDontRelease.java b/test/jdk/java/foreign/dontrelease/TestDontRelease.java index b107c758ba2c..f3f67370b775 100644 --- a/test/jdk/java/foreign/dontrelease/TestDontRelease.java +++ b/test/jdk/java/foreign/dontrelease/TestDontRelease.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,10 @@ * @test * @library ../ /test/lib * @modules java.base/jdk.internal.ref java.base/jdk.internal.foreign - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestDontRelease + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestDontRelease */ import jdk.internal.foreign.MemorySessionImpl; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -38,7 +37,9 @@ import static java.lang.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class TestDontRelease extends NativeTestHelper { diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java index b55664fd7431..aca798c888ef 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java @@ -33,7 +33,7 @@ * panama_jni_use_module/* * * org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule - * @run testng/othervm/native/timeout=180 TestEnableNativeAccess + * @run junit/othervm/native/timeout=180 TestEnableNativeAccess * @summary Basic test for java --enable-native-access */ @@ -43,9 +43,11 @@ import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Basic test of --enable-native-access with expected behaviour: @@ -57,10 +59,9 @@ * (on first access per module only) */ -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestEnableNativeAccess extends TestEnableNativeAccessBase { - @DataProvider(name = "succeedCases") public Object[][] succeedCases() { return new Object[][] { { "panama_enable_native_access", PANAMA_MAIN, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, @@ -111,7 +112,8 @@ OutputAnalyzer run(String action, String cls, Result expectedResult, String... v return outputAnalyzer; } - @Test(dataProvider = "succeedCases") + @ParameterizedTest + @MethodSource("succeedCases") public void testSucceed(String action, String cls, Result expectedResult, String... vmopts) throws Exception { run(action, cls, expectedResult, vmopts); } @@ -120,6 +122,7 @@ public void testSucceed(String action, String cls, Result expectedResult, String * Tests that without --enable-native-access, a multi-line warning is printed * on first access of a module. */ + @Test public void testWarnFirstAccess() throws Exception { List output1 = run("panama_enable_native_access_first", PANAMA_MAIN, successWithWarning("panama")).asLines(); @@ -130,6 +133,7 @@ public void testWarnFirstAccess() throws Exception { * Specifies --enable-native-access more than once, each list of module names * is appended. */ + @Test public void testRepeatedOption() throws Exception { run("panama_enable_native_access_last_one_wins", PANAMA_MAIN, success(), "--enable-native-access=java.base", "--enable-native-access=panama_module"); @@ -141,6 +145,7 @@ public void testRepeatedOption() throws Exception { * Tests invalid values for --enable-native-access and invalid or missing * values for --illegal-native-access. */ + @Test public void testBadValue() throws Exception { run("panama_deny_bad_unknown_module", PANAMA_MAIN, failWithWarning("WARNING: Unknown module: BAD specified to --enable-native-access"), @@ -173,6 +178,7 @@ public void testBadValue() throws Exception { "--illegal-native-access", "bad"); } + @Test public void testDetailedWarningMessage() throws Exception { run("panama_enable_native_access_warn_jni", PANAMA_JNI, success() diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java index a14fd5c12d26..8bc353d14097 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import jdk.test.lib.process.OutputAnalyzer; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class TestEnableNativeAccessBase { static final String MODULE_PATH = System.getProperty("jdk.module.path"); diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java index 2fccb2fa121e..b3118b1cd684 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build TestEnableNativeAccessDynamic * panama_module/* NativeAccessDynamicMain - * @run testng/othervm/timeout=180 TestEnableNativeAccessDynamic + * @run junit/othervm/timeout=180 TestEnableNativeAccessDynamic * @summary Test for dynamically setting --enable-native-access flag for a module */ @@ -39,13 +39,13 @@ import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestEnableNativeAccessDynamic extends TestEnableNativeAccessBase { - @DataProvider(name = "succeedCases") public Object[][] succeedCases() { return new Object[][] { { "panama_enable_native_access", PANAMA_MAIN, successNoWarning() }, @@ -54,7 +54,6 @@ public Object[][] succeedCases() { }; } - @DataProvider(name = "failureCases") public Object[][] failureCases() { String errMsg = "Illegal native access from module panama_module"; return new Object[][] { @@ -92,13 +91,15 @@ OutputAnalyzer run(String action, String moduleAndCls, boolean enableNativeAcces return outputAnalyzer; } - @Test(dataProvider = "succeedCases") + @ParameterizedTest + @MethodSource("succeedCases") public void testSucceed(String action, String moduleAndCls, Result expectedResult) throws Exception { run(action, moduleAndCls, true, expectedResult, false); } - @Test(dataProvider = "failureCases") + @ParameterizedTest + @MethodSource("failureCases") public void testFailures(String action, String moduleAndCls, Result expectedResult) throws Exception { run(action, moduleAndCls, false, expectedResult, false); @@ -106,7 +107,8 @@ public void testFailures(String action, String moduleAndCls, // make sure that having a same named module in boot layer with native access // does not influence same named dynamic module. - @Test(dataProvider = "failureCases") + @ParameterizedTest + @MethodSource("failureCases") public void testFailuresWithPanamaModuleInBootLayer(String action, String moduleAndCls, Result expectedResult) throws Exception { run(action, moduleAndCls, false, expectedResult, true); diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessJarManifest.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessJarManifest.java index 3522921bdd34..3bcd960ccd01 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessJarManifest.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessJarManifest.java @@ -32,7 +32,7 @@ * @build TestEnableNativeAccessJarManifest * panama_module/* * org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule - * @run testng/native TestEnableNativeAccessJarManifest + * @run junit/native TestEnableNativeAccessJarManifest */ import java.nio.file.Files; @@ -47,16 +47,19 @@ import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestEnableNativeAccessJarManifest extends TestEnableNativeAccessBase { private static final String REINVOKER = "TestEnableNativeAccessJarManifest$Reinvoker"; static record Attribute(String name, String value) {} - @Test(dataProvider = "cases") + @ParameterizedTest + @MethodSource("cases") public void testEnableNativeAccessInJarManifest(String action, String cls, Result expectedResult, List attributes, List vmArgs, List programArgs) throws Exception { Manifest man = new Manifest(); @@ -89,7 +92,6 @@ public void testEnableNativeAccessInJarManifest(String action, String cls, Resul checkResult(expectedResult, outputAnalyzer); } - @DataProvider public Object[][] cases() { return new Object[][] { // simple cases where a jar contains a single main class with no dependencies diff --git a/test/jdk/java/foreign/handles/Driver.java b/test/jdk/java/foreign/handles/Driver.java index 63528e19dcbb..1bab9542e18a 100644 --- a/test/jdk/java/foreign/handles/Driver.java +++ b/test/jdk/java/foreign/handles/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,6 @@ /* * @test * @build invoker_module/* lookup_module/* - * @run testng/othervm --illegal-native-access=deny --enable-native-access=invoker_module + * @run junit/othervm --illegal-native-access=deny --enable-native-access=invoker_module * lookup_module/handle.lookup.MethodHandleLookup */ diff --git a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java index f41cf59b07f1..fa9729094cb9 100644 --- a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java +++ b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,16 +37,19 @@ import java.nio.file.Path; import java.util.function.Consumer; -import org.testng.annotations.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class MethodHandleLookup { - @Test(dataProvider = "restrictedMethods") + @ParameterizedTest + @MethodSource("restrictedMethods") public void testRestrictedHandles(MethodHandle handle, String testName) throws Throwable { new handle.invoker.MethodHandleInvoker().call(handle); } - @DataProvider(name = "restrictedMethods") static Object[][] restrictedMethods() { try { return new Object[][]{ diff --git a/test/jdk/java/foreign/handles/lookup_module/module-info.java b/test/jdk/java/foreign/handles/lookup_module/module-info.java index 54efcb071ef7..9a8fade97514 100644 --- a/test/jdk/java/foreign/handles/lookup_module/module-info.java +++ b/test/jdk/java/foreign/handles/lookup_module/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ open module lookup_module { - requires org.testng; + requires org.junit.platform.console.standalone; requires invoker_module; exports handle.lookup; } diff --git a/test/jdk/java/foreign/loaderLookup/TestLoaderLookupJNI.java b/test/jdk/java/foreign/loaderLookup/TestLoaderLookupJNI.java index cb6c0c0bb9e5..22fead8c6e00 100644 --- a/test/jdk/java/foreign/loaderLookup/TestLoaderLookupJNI.java +++ b/test/jdk/java/foreign/loaderLookup/TestLoaderLookupJNI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,15 @@ * questions. */ -import org.testng.annotations.Test; import java.lang.foreign.SymbolLookup; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /* * @test - * @run testng/othervm/native TestLoaderLookupJNI + * @run junit/othervm/native TestLoaderLookupJNI */ public class TestLoaderLookupJNI { diff --git a/test/jdk/java/foreign/loaderLookup/TestSymbolLookupFindOrThrow.java b/test/jdk/java/foreign/loaderLookup/TestSymbolLookupFindOrThrow.java index 146fdbbcf5a0..59f7720cb61f 100644 --- a/test/jdk/java/foreign/loaderLookup/TestSymbolLookupFindOrThrow.java +++ b/test/jdk/java/foreign/loaderLookup/TestSymbolLookupFindOrThrow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,10 +30,9 @@ import java.lang.foreign.SymbolLookup; import java.util.NoSuchElementException; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; final class TestSymbolLookupFindOrThrow { @@ -44,7 +43,7 @@ final class TestSymbolLookupFindOrThrow { @Test void findOrThrow() { MemorySegment symbol = SymbolLookup.loaderLookup().findOrThrow("foo"); - Assertions.assertNotEquals(0, symbol.address()); + assertNotEquals(0, symbol.address()); } @Test diff --git a/test/jdk/java/foreign/nested/TestNested.java b/test/jdk/java/foreign/nested/TestNested.java index 70237bafc133..523fa630dd23 100644 --- a/test/jdk/java/foreign/nested/TestNested.java +++ b/test/jdk/java/foreign/nested/TestNested.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,9 @@ * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" * @build NativeTestHelper - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestNested + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestNested */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; @@ -45,13 +43,19 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestNested extends NativeTestHelper { static { System.loadLibrary("Nested"); } - @Test(dataProvider = "nestedLayouts") + @ParameterizedTest + @MethodSource("nestedLayouts") public void testNested(GroupLayout layout) throws Throwable { try (Arena arena = Arena.ofConfined()) { Random random = new Random(0); @@ -73,7 +77,6 @@ public void testNested(GroupLayout layout) throws Throwable { } } - @DataProvider public static Object[][] nestedLayouts() { List layouts = List.of( S1, U1, U17, S2, S3, S4, S5, S6, U2, S7, U3, U4, U5, U6, U7, S8, S9, U8, U9, U10, S10, diff --git a/test/jdk/java/foreign/normalize/TestNormalize.java b/test/jdk/java/foreign/normalize/TestNormalize.java index b68e43c0705a..1de4da8e5c49 100644 --- a/test/jdk/java/foreign/normalize/TestNormalize.java +++ b/test/jdk/java/foreign/normalize/TestNormalize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,13 @@ /* * @test * @library ../ - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * -Xbatch * -XX:CompileCommand=dontinline,TestNormalize::doCall* * TestNormalize */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.*; import java.lang.invoke.MethodHandle; @@ -45,9 +43,14 @@ import static java.lang.foreign.ValueLayout.JAVA_CHAR; import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_SHORT; -import static org.testng.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; // test normalization of smaller than int primitive types +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestNormalize extends NativeTestHelper { private static final Linker LINKER = Linker.nativeLinker(); @@ -98,7 +101,8 @@ public class TestNormalize extends NativeTestHelper { // When we do either of those, argument normalization should take place, so that the resulting value is sane (1). // After that we convert the value back to int again, the JVM can/will skip value normalization here. // We then check the high order bits of the resulting int. If argument normalization took place at (1), they should all be 0. - @Test(dataProvider = "cases") + @ParameterizedTest + @MethodSource("cases") public void testNormalize(ValueLayout layout, int testValue, int hobMask, MethodHandle toInt, MethodHandle saver) throws Throwable { // use actual type as parameter type to test upcall arg normalization FunctionDescriptor upcallDesc = FunctionDescriptor.ofVoid(layout); @@ -125,8 +129,8 @@ public void testNormalize(ValueLayout layout, int testValue, int hobMask, Method private static void doCall(MethodHandle downcallHandle, MemorySegment upcallStub, int[] box, int dirtyValue, int hobMask) throws Throwable { int result = (int) downcallHandle.invokeExact(upcallStub, dirtyValue); - assertEquals(box[0] & hobMask, 0); // check normalized upcall arg - assertEquals(result & hobMask, 0); // check normalized downcall return value + assertEquals(0, box[0] & hobMask); // check normalized upcall arg + assertEquals(0, result & hobMask); // check normalized downcall return value } public static void saveBooleanAsInt(boolean b, int[] box) { @@ -159,7 +163,6 @@ public static int shortToInt(short s) { return s; } - @DataProvider public static Object[][] cases() { return new Object[][] { { JAVA_BOOLEAN, booleanToInt(true), BOOLEAN_HOB_MASK, BOOLEAN_TO_INT, SAVE_BOOLEAN_AS_INT }, @@ -171,7 +174,8 @@ public static Object[][] cases() { // test which int values are considered true and false // we currently convert any int with a non-zero first byte to true, otherwise false. - @Test(dataProvider = "bools") + @ParameterizedTest + @MethodSource("bools") public void testBool(int testValue, boolean expected) throws Throwable { MemorySegment addr = findNativeOrThrow("test"); MethodHandle target = LINKER.downcallHandle(addr, FunctionDescriptor.of(JAVA_BOOLEAN, ADDRESS, JAVA_INT)); @@ -182,8 +186,8 @@ public void testBool(int testValue, boolean expected) throws Throwable { try (Arena arena = Arena.ofConfined()) { MemorySegment callback = LINKER.upcallStub(upcallTarget, FunctionDescriptor.ofVoid(JAVA_BOOLEAN), arena); boolean result = (boolean) target.invokeExact(callback, testValue); - assertEquals(box[0], expected); - assertEquals(result, expected); + assertEquals(expected, box[0]); + assertEquals(expected, result); } } @@ -191,7 +195,6 @@ private static void saveBoolean(boolean b, boolean[] box) { box[0] = b; } - @DataProvider public static Object[][] bools() { return new Object[][]{ { 0b10, true }, // zero least significant bit, but non-zero first byte diff --git a/test/jdk/java/foreign/normalize/TestNormalizeBooleanVarHandle.java b/test/jdk/java/foreign/normalize/TestNormalizeBooleanVarHandle.java index acca0d095c30..567fec7ccb88 100644 --- a/test/jdk/java/foreign/normalize/TestNormalizeBooleanVarHandle.java +++ b/test/jdk/java/foreign/normalize/TestNormalizeBooleanVarHandle.java @@ -23,11 +23,9 @@ /* * @test - * @run testng TestNormalizeBooleanVarHandle + * @run junit TestNormalizeBooleanVarHandle */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -38,14 +36,20 @@ import java.util.function.Predicate; import static java.lang.foreign.ValueLayout.*; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; // test normalization of smaller than int primitive types +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestNormalizeBooleanVarHandle { static final VarHandle VH = JAVA_BOOLEAN.varHandle(); - @Test(dataProvider = "bools") + @ParameterizedTest + @MethodSource("bools") public void testBool(Function segmentFactory, Predicate accessor, byte testValue, boolean expected) { try (Arena arena = Arena.ofConfined()) { @@ -53,11 +57,10 @@ public void testBool(Function segmentFactory, Predicate cases = new ArrayList<>(); for (Function segmentFactory : factories()) { diff --git a/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java b/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java index 1f63d7bfe231..b3f23b1230d6 100644 --- a/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java +++ b/test/jdk/java/foreign/passheapsegment/TestPassHeapSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,9 @@ /* * @test * @library ../ /test/lib - * @run testng/othervm/native --enable-native-access=ALL-UNNAMED TestPassHeapSegment + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED TestPassHeapSegment */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.lang.foreign.*; @@ -36,22 +34,32 @@ import static java.lang.foreign.ValueLayout.ADDRESS; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestPassHeapSegment extends UpcallTestHelper { static { System.loadLibrary("PassHeapSegment"); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void testNoHeapArgs() throws Throwable { MethodHandle handle = downcallHandle("test_args", FunctionDescriptor.ofVoid(ADDRESS)); MemorySegment segment = MemorySegment.ofArray(new byte[]{ 0, 1, 2 }); - handle.invoke(segment); // should throw + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + handle.invoke(segment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + @Test public void testNoHeapCaptureCallState() throws Throwable { MethodHandle handle = downcallHandle("test_args", FunctionDescriptor.ofVoid(ADDRESS), Linker.Option.captureCallState("errno")); @@ -59,11 +67,15 @@ public void testNoHeapCaptureCallState() throws Throwable { assert Linker.Option.captureStateLayout().byteAlignment() % 4 == 0; MemorySegment captureHeap = MemorySegment.ofArray(new int[(int) Linker.Option.captureStateLayout().byteSize() / 4]); MemorySegment segment = arena.allocateFrom(C_CHAR, new byte[]{ 0, 1, 2 }); - handle.invoke(captureHeap, segment); // should throw for captureHeap + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { + handle.invoke(captureHeap, segment); + }); + assertTrue(e.getMessage().matches(".*Heap segment not allowed.*")); } } - @Test(dataProvider = "specs") + @ParameterizedTest + @MethodSource("specs") public void testNoHeapReturns(boolean spec) throws IOException, InterruptedException { runInNewProcess(Runner.class, spec) .shouldNotHaveExitValue(0) @@ -87,7 +99,6 @@ public static MemorySegment target() { } } - @DataProvider public static Object[][] specs() { return new Object[][]{ { true }, diff --git a/test/jdk/java/foreign/virtual/TestVirtualCalls.java b/test/jdk/java/foreign/virtual/TestVirtualCalls.java index ddb4eb666949..931ce3ff5b19 100644 --- a/test/jdk/java/foreign/virtual/TestVirtualCalls.java +++ b/test/jdk/java/foreign/virtual/TestVirtualCalls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @library ../ - * @run testng/othervm/native + * @run junit/othervm/native * --enable-native-access=ALL-UNNAMED * TestVirtualCalls */ @@ -35,9 +35,9 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; -import org.testng.annotations.*; - -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; public class TestVirtualCalls extends NativeTestHelper { @@ -60,14 +60,16 @@ public class TestVirtualCalls extends NativeTestHelper { @Test public void testVirtualCalls() throws Throwable { - assertEquals((int) func.invokeExact(funcA), 1); - assertEquals((int) func.invokeExact(funcB), 2); - assertEquals((int) func.invokeExact(funcC), 3); + assertEquals(1, (int) func.invokeExact(funcA)); + assertEquals(2, (int) func.invokeExact(funcB)); + assertEquals(3, (int) func.invokeExact(funcC)); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullTarget() throws Throwable { - int x = (int) func.invokeExact((MemorySegment)null); + assertThrows(NullPointerException.class, () -> { + int x = (int) func.invokeExact((MemorySegment)null); + }); } } From c041b09de3ab3ea7fc13180ae4244ecfdfe5ab6c Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Wed, 26 Aug 2026 15:34:19 +0000 Subject: [PATCH 090/223] 8390350: Remove test-local verbose mode from vmTestbase nsk tests Reviewed-by: coleenp, sspitsyn, lmesnik --- .../Accessible/isPrivate/isPrivate001.java | 6 +- .../isPrivate001/TestDescription.java | 1 - .../Accessible/isPrivate/isPrivate001a.java | 26 ++----- .../isProtected/isProtected001.java | 6 +- .../isProtected001/TestDescription.java | 1 - .../isProtected/isProtected001a.java | 26 ++----- .../jdi/Accessible/isPublic/isPublic001.java | 6 +- .../isPublic/isPublic001/TestDescription.java | 1 - .../jdi/Accessible/isPublic/isPublic001a.java | 26 ++----- .../Accessible/modifiers/modifiers001.java | 6 +- .../modifiers001/TestDescription.java | 1 - .../Accessible/modifiers/modifiers001a.java | 26 ++----- .../reflectedType/reflectype001.java | 6 +- .../reflectype001/TestDescription.java | 1 - .../reflectedType/reflectype001a.java | 26 ++----- .../reflectype002/TestDescription.java | 1 - .../reflectedType/reflectype002a.java | 43 ++++------- .../allfields001/TestDescription.java | 1 - .../allFields/allfields001a.java | 29 ++------ .../ReferenceType/allFields/allfields002.java | 6 +- .../allfields002/TestDescription.java | 1 - .../allFields/allfields002a.java | 33 ++------- .../allfields003/TestDescription.java | 1 - .../allFields/allfields003a.java | 50 +++++-------- .../allfields004/TestDescription.java | 1 - .../allFields/allfields004a.java | 28 ++----- .../allmethods001/TestDescription.java | 1 - .../allMethods/allmethods001a.java | 36 +++------ .../allMethods/allmethods002.java | 6 +- .../allmethods002/TestDescription.java | 1 - .../allMethods/allmethods002a.java | 33 ++------- .../allmethods003/TestDescription.java | 1 - .../allMethods/allmethods003a.java | 43 ++++------- .../allmethods004/TestDescription.java | 1 - .../allMethods/allmethods004a.java | 28 ++----- .../classobj001/TestDescription.java | 1 - .../classObject/classobj001a.java | 27 ++----- .../classobj002/TestDescription.java | 1 - .../classObject/classobj002a.java | 43 ++++------- .../equals/equals001/TestDescription.java | 1 - .../jdi/ReferenceType/equals/equals001a.java | 28 ++----- .../equals/equals002/TestDescription.java | 1 - .../jdi/ReferenceType/equals/equals002a.java | 43 ++++------- .../TestDescription.java | 1 - .../failedToInitialize001a.java | 32 ++------ .../failedtoinit002/TestDescription.java | 1 - .../failedToInitialize/failedtoinit002a.java | 43 ++++------- .../fieldbyname001/TestDescription.java | 1 - .../fieldByName/fieldbyname001a.java | 29 ++------ .../fieldByName/fieldbyname002.java | 6 +- .../fieldbyname002/TestDescription.java | 1 - .../fieldByName/fieldbyname002a.java | 33 ++------- .../fieldbyname003/TestDescription.java | 1 - .../fieldByName/fieldbyname003a.java | 43 ++++------- .../fields/fields001/TestDescription.java | 1 - .../jdi/ReferenceType/fields/fields001a.java | 29 ++------ .../jdi/ReferenceType/fields/fields002.java | 73 ++++++------------- .../fields/fields002/TestDescription.java | 1 - .../jdi/ReferenceType/fields/fields002a.java | 33 ++------- .../fields/fields003/TestDescription.java | 1 - .../jdi/ReferenceType/fields/fields003a.java | 43 ++++------- .../fields/fields004/TestDescription.java | 1 - .../jdi/ReferenceType/fields/fields004a.java | 28 ++----- .../hashCode/hashcode001/TestDescription.java | 1 - .../ReferenceType/hashCode/hashcode001a.java | 28 ++----- .../hashCode/hashcode002/TestDescription.java | 1 - .../ReferenceType/hashCode/hashcode002a.java | 43 ++++------- .../isAbstract001/TestDescription.java | 1 - .../isAbstract/isAbstract001a.java | 26 ++----- .../isabstract002/TestDescription.java | 1 - .../isAbstract/isabstract002a.java | 43 ++++------- .../isInitialized/isinit001.java | 5 -- .../isinit001/TestDescription.java | 1 - .../isInitialized/isinit001a.java | 28 ++----- .../isinit002/TestDescription.java | 1 - .../isInitialized/isinit002a.java | 46 +++++------- .../isPrepared/isprepared001.java | 4 - .../isprepared001/TestDescription.java | 1 - .../isPrepared/isprepared001a.java | 28 ++----- .../isprepared002/TestDescription.java | 1 - .../isPrepared/isprepared002a.java | 43 ++++------- .../isVerified/isVerified001.java | 6 -- .../isVerified001/TestDescription.java | 1 - .../isVerified/isVerified001a.java | 26 ++----- .../isverified002/TestDescription.java | 1 - .../isVerified/isverified002a.java | 44 ++++------- .../methods/methods001/TestDescription.java | 1 - .../ReferenceType/methods/methods001a.java | 36 +++------ .../jdi/ReferenceType/methods/methods002.java | 73 ++++++------------- .../methods/methods002/TestDescription.java | 1 - .../ReferenceType/methods/methods002a.java | 32 ++------ .../methods/methods003/TestDescription.java | 1 - .../ReferenceType/methods/methods003a.java | 43 ++++------- .../methods/methods004/TestDescription.java | 1 - .../ReferenceType/methods/methods004a.java | 28 ++----- .../methbyname_s001/TestDescription.java | 1 - .../methodsByName_s/methbyname_s001a.java | 37 +++------- .../methodsByName_s/methbyname_s002.java | 9 +-- .../methbyname_s002/TestDescription.java | 1 - .../methodsByName_s/methbyname_s002a.java | 33 ++------- .../methbyname_s003/TestDescription.java | 1 - .../methodsByName_s/methbyname_s003a.java | 43 ++++------- .../methbyname_s004/TestDescription.java | 1 - .../methodsByName_s/methbyname_s004a.java | 37 +++------- .../methbyname_ss001/TestDescription.java | 1 - .../methodsByName_ss/methbyname_ss001a.java | 37 +++------- .../methodsByName_ss/methbyname_ss002.java | 8 +- .../methbyname_ss002/TestDescription.java | 1 - .../methodsByName_ss/methbyname_ss002a.java | 33 ++------- .../methbyname_ss003/TestDescription.java | 1 - .../methodsByName_ss/methbyname_ss003a.java | 43 ++++------- .../name/name001/TestDescription.java | 1 - .../nsk/jdi/ReferenceType/name/name001a.java | 28 ++----- .../name/name002/TestDescription.java | 1 - .../nsk/jdi/ReferenceType/name/name002a.java | 43 ++++------- .../sourcename001/TestDescription.java | 1 - .../sourceName/sourcename001a.java | 27 ++----- .../sourcename002/TestDescription.java | 1 - .../sourceName/sourcename002a.java | 46 +++++------- .../sourcename003/TestDescription.java | 1 - .../sourceName/sourcename003a.java | 27 ++----- .../visibfield001/TestDescription.java | 1 - .../visibleFields/visibfield001a.java | 29 ++------ .../visibleFields/visibfield002.java | 8 +- .../visibfield002/TestDescription.java | 1 - .../visibleFields/visibfield002a.java | 33 ++------- .../visibfield003/TestDescription.java | 1 - .../visibleFields/visibfield003a.java | 43 ++++------- .../visibfield004/TestDescription.java | 1 - .../visibleFields/visibfield004a.java | 28 ++----- .../visibmethod001/TestDescription.java | 1 - .../visibleMethods/visibmethod001a.java | 36 +++------ .../visibleMethods/visibmethod002.java | 8 +- .../visibmethod002/TestDescription.java | 1 - .../visibleMethods/visibmethod002a.java | 33 ++------- .../visibmethod003/TestDescription.java | 1 - .../visibleMethods/visibmethod003a.java | 43 ++++------- .../visibmethod004/TestDescription.java | 1 - .../visibleMethods/visibmethod004a.java | 28 ++----- .../visibmethod005/TestDescription.java | 1 - .../visibleMethods/visibmethod005a.java | 35 +++------ .../classesByName/classesbyname001.java | 6 +- .../classesbyname001/TestDescription.java | 1 - .../classesByName/classesbyname001a.java | 39 ++-------- 144 files changed, 684 insertions(+), 1809 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001.java index d945672439fd..1659241ead5a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001.java @@ -133,11 +133,7 @@ private int runThis (String argv[], PrintStream out) { Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001/TestDescription.java index eb4569cda0bc..cc4c1f334d3d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001/TestDescription.java @@ -50,7 +50,6 @@ * nsk.jdi.Accessible.isPrivate.isPrivate001a * @run driver * nsk.jdi.Accessible.isPrivate.isPrivate001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001a.java index 163b687a9827..836f6d4ec15b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPrivate/isPrivate001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isPrivate001 JDI test. */ public class isPrivate001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -82,31 +81,18 @@ private static class s_interf_impl implements s_interf {} pack_priv_interf_impl ppii0 = new pack_priv_interf_impl(); pack_priv_interf ppi0, ppi1[]={ppi0}, ppi2[][]={ppi1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isPrivate001a: debugee started!"); + log.display("**> isPrivate001a: debugee started!"); isPrivate001a isPrivate001a_obj = new isPrivate001a(); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isPrivate001a: waiting for \"quit\" signal..."); + log.display("**> isPrivate001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isPrivate001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isPrivate001a: completed succesfully!"); + log.display("**> isPrivate001a: \"quit\" signal recieved!"); + log.display("**> isPrivate001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isPrivate001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001.java index 49780d19b271..fb20a97549b6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001.java @@ -133,11 +133,7 @@ private int runThis (String argv[], PrintStream out) { Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001/TestDescription.java index 3f16eb2378bf..9fbeb819257a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001/TestDescription.java @@ -49,7 +49,6 @@ * nsk.jdi.Accessible.isProtected.isProtected001a * @run driver * nsk.jdi.Accessible.isProtected.isProtected001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001a.java index 361456d2ed52..6f41500ac087 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isProtected/isProtected001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isProtected001 JDI test. */ public class isProtected001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -82,31 +81,18 @@ protected static class s_interf_impl implements s_interf {} pack_priv_interf_impl ppii0 = new pack_priv_interf_impl(); pack_priv_interf ppi0, ppi1[]={ppi0}, ppi2[][]={ppi1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isProtected001a: debugee started!"); + log.display("**> isProtected001a: debugee started!"); isProtected001a isProtected001a_obj = new isProtected001a(); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isProtected001a: waiting for \"quit\" signal..."); + log.display("**> isProtected001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isProtected001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isProtected001a: completed succesfully!"); + log.display("**> isProtected001a: \"quit\" signal recieved!"); + log.display("**> isProtected001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isProtected001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001.java index 0238dc5e6a06..d52ae0f96374 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001.java @@ -133,11 +133,7 @@ private int runThis (String argv[], PrintStream out) { Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001/TestDescription.java index 50fe8fd80156..afa48f784633 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001/TestDescription.java @@ -49,7 +49,6 @@ * nsk.jdi.Accessible.isPublic.isPublic001a * @run driver * nsk.jdi.Accessible.isPublic.isPublic001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001a.java index 65493885ae0d..2d3307508d64 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/isPublic/isPublic001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isPublic001 JDI test. */ public class isPublic001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -81,31 +80,18 @@ protected static class s_interf_impl implements s_interf {} pack_priv_interf_impl ppii0 = new pack_priv_interf_impl(); pack_priv_interf ppi0, ppi1[]={ppi0}, ppi2[][]={ppi1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isPublic001a: debugee started!"); + log.display("**> isPublic001a: debugee started!"); isPublic001a isPublic001a_obj = new isPublic001a(); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isPublic001a: waiting for \"quit\" signal..."); + log.display("**> isPublic001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isPublic001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isPublic001a: completed succesfully!"); + log.display("**> isPublic001a: \"quit\" signal recieved!"); + log.display("**> isPublic001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isPublic001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001.java index a8d22483ad87..00dcac2720ea 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001.java @@ -125,11 +125,7 @@ private int runThis (String argv[], PrintStream out) { Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001/TestDescription.java index dc00a5d81cfc..08190bf75fcf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001/TestDescription.java @@ -50,7 +50,6 @@ * nsk.jdi.Accessible.modifiers.modifiers001a * @run driver * nsk.jdi.Accessible.modifiers.modifiers001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001a.java index 19d2081780e9..45422a5ca3a7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Accessible/modifiers/modifiers001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the modifiers001 JDI test. */ public class modifiers001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); // Classes must be loaded and linked, so all fields must be // initialized @@ -73,31 +72,18 @@ static class s_interf_impl implements s_interf {} interf_impl m_interf_impl_0 = new interf_impl(); interf m_interf_0, m_interf_1[] = {m_interf_0}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i modifiers001a: debugee started!"); + log.display("**> modifiers001a: debugee started!"); modifiers001a obj = new modifiers001a(); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> modifiers001a: waiting for \"quit\" signal..."); + log.display("**> modifiers001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> modifiers001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> modifiers001a: completed succesfully!"); + log.display("**> modifiers001a: \"quit\" signal recieved!"); + log.display("**> modifiers001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> modifiers001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001.java index 501f38358d86..cf521bd6dff8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001.java @@ -128,11 +128,7 @@ private int runThis (String argv[], PrintStream out) { Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001/TestDescription.java index 7c0dfd0e82bf..02a3adb50bcc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001/TestDescription.java @@ -53,7 +53,6 @@ * nsk.jdi.ClassObjectReference.reflectedType.reflectype001a * @run driver * nsk.jdi.ClassObjectReference.reflectedType.reflectype001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001a.java index 9bc458b9bb7b..e53fc8248ec6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the reflectype001 JDI test. */ public class reflectype001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -75,33 +73,21 @@ class package_interf_impl implements package_interf {} package_interf_impl pii0 = new package_interf_impl(); package_interf package_interf0, package_interf1[]={package_interf0}, package_interf2[][]={package_interf1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } public static void main (String argv[]) { - for (int i=0; i reflectype001a: debugee started!"); + log.display("**> reflectype001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); reflectype001a reflectype001a_obj = new reflectype001a(); - print_log_on_verbose("**> reflectype001a: waiting for \"quit\" signal..."); + log.display("**> reflectype001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> reflectype001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> reflectype001a: completed succesfully!"); + log.display("**> reflectype001a: \"quit\" signal recieved!"); + log.display("**> reflectype001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> reflectype001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java index efec917716a0..a261fa366511 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ClassObjectReference.reflectedType.reflectype002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002a.java index 0f5cda757519..11cee2ff1fd5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassObjectReference/reflectedType/reflectype002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,59 +29,48 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the reflectype002 JDI test. */ public class reflectype002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ClassObjectReference.reflectedType."; private final static String checked_class_name = package_prefix + "reflectype002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> reflectype002a: debugee started!"); + log.display("**> reflectype002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; - print_log_on_verbose("**> reflectype002a: waiting for \"checked class dir\" info..."); + log.display("**> reflectype002a: waiting for \"checked class dir\" info..."); ClassUnloader classUnloader = new ClassUnloader(); try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> reflectype002a: checked class loaded:" + checked_class_name); + log.display("--> reflectype002a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> reflectype002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> reflectype002a: checked class NOT loaded:" + checked_class_name); + log.display("--> reflectype002a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> reflectype002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> reflectype002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> reflectype002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> reflectype002a: completed!"); + log.display("**> reflectype002a: \"quit\" signal recieved!"); + log.display("**> reflectype002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -91,24 +80,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> reflectype002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> reflectype002a: enforce to unload checked class..."); + log.display("**> reflectype002a: \"continue\" signal recieved!"); + log.display("**> reflectype002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> reflectype002a: checked class may be NOT unloaded!"); + log.display("**> reflectype002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> reflectype002a: checked class unloaded!"); + log.display("**> reflectype002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> reflectype002a: waiting for \"quit\" signal..."); + log.display("**> reflectype002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> reflectype002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> reflectype002a: completed!"); + log.display("**> reflectype002a: \"quit\" signal recieved!"); + log.display("**> reflectype002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> reflectype002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001/TestDescription.java index fe0c781b56f8..b6d4d052ed31 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.allFields.allfields001a * @run driver * nsk.jdi.ReferenceType.allFields.allfields001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001a.java index 8fa0790cc716..b07bb2f291cc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allfields001 JDI test. */ public class allfields001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i allfields001a: debugee started!"); + log.display("**> allfields001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); allfields001aClassForCheck class_for_check = new allfields001aClassForCheck(); - print_log_on_verbose("**> allfields001a: waiting for \"quit\" signal..."); + log.display("**> allfields001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allfields001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allfields001a: completed succesfully!"); + log.display("**> allfields001a: \"quit\" signal recieved!"); + log.display("**> allfields001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allfields001a: unexpected signal (no \"quit\") - " + instruction); @@ -158,5 +142,4 @@ interface allfields001aInterfaceForCheck { static final long ambiguous_prim_field = 1; static final Object ambiguous_ref_field = new Object(); - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002.java index ee94fd88bc42..53175b0e6edb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002.java @@ -100,11 +100,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/allFields/allfields002 test LOG:"); print_log_on_verbose("==> test checks allFields() method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002/TestDescription.java index feb95cf9a76a..0e4ef769249b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.allFields.allfields002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002a.java index eb4e99cd953b..5d0030cde684 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,35 +28,20 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the allfields002 JDI test. */ public class allfields002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.allFields."; private final static String checked_class_name = package_prefix + "allfields002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i allfields002a: debugee started!"); + log.display("**> allfields002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,19 +50,17 @@ public static void main (String argv[]) { allfields002aClassLoader customClassLoader = new allfields002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> allfields002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> allfields002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> allfields002a: checked class NOT loaded: " + e); + log.display("--> allfields002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> allfields002a: waiting for \"quit\" signal..."); + log.display("**> allfields002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allfields002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allfields002a: completed succesfully!"); + log.display("**> allfields002a: \"quit\" signal recieved!"); + log.display("**> allfields002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allfields002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java index 053a6ff34c52..904e0ff4e3ef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.allFields.allfields003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003a.java index 68b88e0af6c3..0cdd206d069a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,63 +29,49 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allfields003 JDI test. */ public class allfields003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - + private static Log log = new Log(System.err); static String package_prefix = "nsk.jdi.ReferenceType.allFields."; static String checked_class_name = package_prefix + "allfields003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> allfields003a: debugee started!"); + log.display("**> allfields003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> allfields003a: waiting for \"checked class dir\" info..."); + log.display("**> allfields003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; - print_log_on_verbose - ("--> allfields003a: checked class dir:" + checked_class_dir); + log.display("--> allfields003a: checked class dir:" + checked_class_dir); ClassUnloader classUnloader = new ClassUnloader(); try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> allfields003a: checked class loaded:" + checked_class_name); + log.display("--> allfields003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException - print_log_on_verbose - ("**> allfields003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> allfields003a: checked class NOT loaded:" + checked_class_name); + log.display("**> allfields003a: load class: exception thrown = " + e.toString()); + log.display("--> allfields003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> allfields003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> allfields003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allfields003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allfields003a: completed!"); + log.display("**> allfields003a: \"quit\" signal recieved!"); + log.display("**> allfields003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -95,24 +81,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> allfields003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> allfields003a: enforce to unload checked class..."); + log.display("**> allfields003a: \"continue\" signal recieved!"); + log.display("**> allfields003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> allfields003a: checked class may be NOT unloaded!"); + log.display("**> allfields003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> allfields003a: checked class unloaded!"); + log.display("**> allfields003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> allfields003a: waiting for \"quit\" signal..."); + log.display("**> allfields003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allfields003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allfields003a: completed!"); + log.display("**> allfields003a: \"quit\" signal recieved!"); + log.display("**> allfields003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allfields003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004/TestDescription.java index d21c2c2aa06c..6415b2eb96e8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.allFields.allfields004a * @run driver * nsk.jdi.ReferenceType.allFields.allfields004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004a.java index 2384484e59ca..9c72ed26c713 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allFields/allfields004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allfields004 JDI test. */ public class allfields004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i allfields004a: debugee started!"); + log.display("**> allfields004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); allfields004aClassForCheck class_for_check = new allfields004aClassForCheck(); - print_log_on_verbose("**> allfields004a: waiting for \"quit\" signal..."); + log.display("**> allfields004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allfields004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allfields004a: completed succesfully!"); + log.display("**> allfields004a: \"quit\" signal recieved!"); + log.display("**> allfields004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> allfields004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001/TestDescription.java index b5b0ab74d9ee..9cadf25e457e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.allMethods.allmethods001a * @run driver * nsk.jdi.ReferenceType.allMethods.allmethods001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001a.java index 963609fa7df6..16eaeceb46a0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allmethods001 JDI test. */ public class allmethods001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.allMethods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "allmethods001aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i allmethods001a: debugee started!"); + log.display("**> allmethods001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, allmethods001a.class.getClassLoader()); - print_log_on_verbose - ("--> allmethods001a: checked class loaded:" + checked_class_name); + log.display("--> allmethods001a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> allmethods001a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> allmethods001a: checked class NOT loaded: " + checked_class_name); + log.display("--> allmethods001a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> allmethods001a: waiting for \"quit\" signal..."); + log.display("**> allmethods001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allmethods001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allmethods001a: completed succesfully!"); + log.display("**> allmethods001a: \"quit\" signal recieved!"); + log.display("**> allmethods001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allmethods001a: unexpected signal (no \"quit\") - " + instruction); @@ -196,7 +179,6 @@ public void i_interf_overridden_void_par_method(int i) {} // static initializer static {} - } abstract class allmethods001aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002.java index 856366d67e0d..cbf1382e43a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002.java @@ -103,11 +103,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/allMethods/allmethods002 test LOG:"); print_log_on_verbose("==> test checks allMethods() method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002/TestDescription.java index f5478f4c0e3c..3b79856a33d0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.allMethods.allmethods002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002a.java index 0ea324a2aa54..10c9e7205061 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the allmethods002 JDI test. */ public class allmethods002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.allMethods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "allmethods002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i allmethods002a: debugee started!"); + log.display("**> allmethods002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { allmethods002aClassLoader customClassLoader = new allmethods002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> allmethods002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> allmethods002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> allmethods002a: checked class NOT loaded: " + e); + log.display("--> allmethods002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> allmethods002a: waiting for \"quit\" signal..."); + log.display("**> allmethods002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allmethods002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allmethods002a: completed succesfully!"); + log.display("**> allmethods002a: \"quit\" signal recieved!"); + log.display("**> allmethods002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allmethods002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java index a0e8bd2b7f15..dddea049634a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.allMethods.allmethods003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003a.java index f8a7af6b7177..211c980ecb0b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allmethods003 JDI test. */ public class allmethods003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); static String package_prefix = "nsk.jdi.ReferenceType.allMethods."; static String checked_class_name = package_prefix + "allmethods003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> allmethods003a: debugee started!"); + log.display("**> allmethods003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> allmethods003a: waiting for \"checked class dir\" info..."); + log.display("**> allmethods003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -65,23 +56,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> allmethods003a: checked class loaded:" + checked_class_name); + log.display("--> allmethods003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> allmethods003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> allmethods003a: checked class NOT loaded:" + checked_class_name); + log.display("--> allmethods003a: checked class NOT loaded:" + checked_class_name); // Debugger finds this fact itself } - print_log_on_verbose("**> allmethods003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> allmethods003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allmethods003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allmethods003a: completed!"); + log.display("**> allmethods003a: \"quit\" signal recieved!"); + log.display("**> allmethods003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -91,24 +80,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> allmethods003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> allmethods003a: enforce to unload checked class..."); + log.display("**> allmethods003a: \"continue\" signal recieved!"); + log.display("**> allmethods003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> allmethods003a: checked class may be NOT unloaded!"); + log.display("**> allmethods003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> allmethods003a: checked class unloaded!"); + log.display("**> allmethods003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> allmethods003a: waiting for \"quit\" signal..."); + log.display("**> allmethods003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allmethods003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allmethods003a: completed!"); + log.display("**> allmethods003a: \"quit\" signal recieved!"); + log.display("**> allmethods003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> allmethods003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004/TestDescription.java index f6981d4a6e91..db60ddd2eee7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004/TestDescription.java @@ -45,7 +45,6 @@ * nsk.jdi.ReferenceType.allMethods.allmethods004a * @run driver * nsk.jdi.ReferenceType.allMethods.allmethods004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004a.java index c7d94273b10d..bf4da3b2d028 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/allMethods/allmethods004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the allmethods004 JDI test. */ public class allmethods004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i allmethods004a: debugee started!"); + log.display("**> allmethods004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); allmethods004aClassForCheck class_for_check = new allmethods004aClassForCheck(); - print_log_on_verbose("**> allmethods004a: waiting for \"quit\" signal..."); + log.display("**> allmethods004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> allmethods004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> allmethods004a: completed succesfully!"); + log.display("**> allmethods004a: \"quit\" signal recieved!"); + log.display("**> allmethods004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> allmethods004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001/TestDescription.java index 7da86a967382..7f5c8bdbe4a5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001/TestDescription.java @@ -44,7 +44,6 @@ * nsk.jdi.ReferenceType.classObject.classobj001a * @run driver * nsk.jdi.ReferenceType.classObject.classobj001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001a.java index 8c9f3d6d05e5..84d1cf4e63cc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the classobj001 JDI test. */ public class classobj001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -75,33 +73,20 @@ static class s_interf_impl implements s_interf {} package_interf package_interf0, package_interf1[]={package_interf0}, package_interf2[][]={package_interf1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i classobj001a: debugee started!"); + log.display("**> classobj001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); classobj001a classobj001a_obj = new classobj001a(); - print_log_on_verbose("**> classobj001a: waiting for \"quit\" signal..."); + log.display("**> classobj001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> classobj001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> classobj001a: completed succesfully!"); + log.display("**> classobj001a: \"quit\" signal recieved!"); + log.display("**> classobj001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> classobj001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java index ab751a1f29c3..08376ce6d6fa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.classObject.classobj002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002a.java index 2d9b1bce94d2..c54522ee97bf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classObject/classobj002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the classobj002 JDI test. */ public class classobj002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.classObject."; private final static String checked_class_name = package_prefix + "classobj002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> classobj002a: debugee started!"); + log.display("**> classobj002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> classobj002a: waiting for \"checked class dir\" info..."); + log.display("**> classobj002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -65,23 +56,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> classobj002a: checked class loaded:" + checked_class_name); + log.display("--> classobj002a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> classobj002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> classobj002a: checked class NOT loaded:" + checked_class_name); + log.display("--> classobj002a: checked class NOT loaded:" + checked_class_name); // Debugger finds this fact itself } - print_log_on_verbose("**> classobj002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> classobj002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> classobj002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> classobj002a: completed!"); + log.display("**> classobj002a: \"quit\" signal recieved!"); + log.display("**> classobj002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -91,24 +80,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> classobj002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> classobj002a: enforce to unload checked class..."); + log.display("**> classobj002a: \"continue\" signal recieved!"); + log.display("**> classobj002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> classobj002a: checked class may be NOT unloaded!"); + log.display("**> classobj002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> classobj002a: checked class unloaded!"); + log.display("**> classobj002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> classobj002a: waiting for \"quit\" signal..."); + log.display("**> classobj002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> classobj002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> classobj002a: completed!"); + log.display("**> classobj002a: \"quit\" signal recieved!"); + log.display("**> classobj002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> classobj002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001/TestDescription.java index 1b1aff020cb1..fc8de81a532c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001/TestDescription.java @@ -50,7 +50,6 @@ * nsk.jdi.ReferenceType.equals.equals001a * @run driver * nsk.jdi.ReferenceType.equals.equals001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001a.java index 75551cc35466..7d3c5bfd9a37 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,16 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the equals001 JDI test. */ public class equals001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -77,33 +74,20 @@ static class s_interf_impl implements s_interf {} interf_for_check1[]={interf_for_check0}, interf_for_check2[][]={interf_for_check1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i equals001a: debugee started!"); + log.display("**> equals001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); equals001a equals001a_obj = new equals001a(); - print_log_on_verbose("**> equals001a: waiting for \"quit\" signal..."); + log.display("**> equals001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> equals001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> equals001a: completed succesfully!"); + log.display("**> equals001a: \"quit\" signal recieved!"); + log.display("**> equals001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> equals001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java index e1c25e9dbdd4..986d130214d2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.equals.equals002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002a.java index 0fc1f3a28182..292934aae9e6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/equals/equals002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the equals002 JDI test. */ public class equals002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.equals."; private final static String checked_class_name = package_prefix + "equals002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> equals002a: debugee started!"); + log.display("**> equals002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> equals002a: waiting for \"checked class dir\" info..."); + log.display("**> equals002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> equals002a: checked class loaded:" + checked_class_name); + log.display("--> equals002a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> equals002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> equals002a: checked class NOT loaded:" + checked_class_name); + log.display("--> equals002a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> equals002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> equals002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> equals002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> equals002a: completed!"); + log.display("**> equals002a: \"quit\" signal recieved!"); + log.display("**> equals002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> equals002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> equals002a: enforce to unload checked class..."); + log.display("**> equals002a: \"continue\" signal recieved!"); + log.display("**> equals002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> equals002a: checked class may be NOT unloaded!"); + log.display("**> equals002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> equals002a: checked class unloaded!"); + log.display("**> equals002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> equals002a: waiting for \"quit\" signal..."); + log.display("**> equals002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> equals002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> equals002a: completed!"); + log.display("**> equals002a: \"quit\" signal recieved!"); + log.display("**> equals002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> equals002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001/TestDescription.java index a1d0665a88b8..08cbf8c05c05 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001/TestDescription.java @@ -43,7 +43,6 @@ * nsk.jdi.ReferenceType.failedToInitialize.failedToInitialize001a * @run driver * nsk.jdi.ReferenceType.failedToInitialize.failedToInitialize001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001a.java index f8c801e881c6..bebc8fb84c62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedToInitialize001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the failedToInitialize001 JDI test. */ public class failedToInitialize001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); failedToInitialize001 a001_0=new failedToInitialize001(); @@ -43,22 +42,9 @@ public class failedToInitialize001a { interf_impl interf_impl_0 = new interf_impl(); interf interf_0, interf_1[]={interf_0}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i failedToInitialize001a: debugee started!"); + log.display("**> failedToInitialize001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -71,8 +57,7 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } catch (ExceptionInInitializerError e) { - print_log_on_verbose - ("**> failedToInitialize001a: ExceptionInInitializerError caught (fail_init_class)!"); + log.display("**> failedToInitialize001a: ExceptionInInitializerError caught (fail_init_class)!"); } try { @@ -83,16 +68,15 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } catch (ExceptionInInitializerError e) { - print_log_on_verbose - ("**> failedToInitialize001a: ExceptionInInitializerError caught (fail_init_subcl)!"); + log.display("**> failedToInitialize001a: ExceptionInInitializerError caught (fail_init_subcl)!"); } - print_log_on_verbose("**> failedToInitialize001a: waiting for \"quit\" signal..."); + log.display("**> failedToInitialize001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> failedToInitialize001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> failedToInitialize001a: completed succesfully!"); + log.display("**> failedToInitialize001a: \"quit\" signal recieved!"); + log.display("**> failedToInitialize001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> failedToInitialize001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java index 703bb6c54aa8..701b4b183c00 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.failedToInitialize.failedtoinit002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002a.java index cbd88e242365..6a8e678f2236 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/failedToInitialize/failedtoinit002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the failedtoinit002 JDI test. */ public class failedtoinit002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.failedToInitialize."; private final static String checked_class_name = package_prefix + "failedtoinit002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> failedtoinit002a: debugee started!"); + log.display("**> failedtoinit002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> failedtoinit002a: waiting for \"checked class dir\" info..."); + log.display("**> failedtoinit002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> failedtoinit002a: checked class loaded: " + checked_class_name); + log.display("--> failedtoinit002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> failedtoinit002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> failedtoinit002a: checked class NOT loaded: " + checked_class_name); + log.display("--> failedtoinit002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> failedtoinit002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> failedtoinit002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> failedtoinit002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> failedtoinit002a: completed!"); + log.display("**> failedtoinit002a: \"quit\" signal recieved!"); + log.display("**> failedtoinit002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> failedtoinit002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> failedtoinit002a: enforce to unload checked class..."); + log.display("**> failedtoinit002a: \"continue\" signal recieved!"); + log.display("**> failedtoinit002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> failedtoinit002a: checked class may be NOT unloaded!"); + log.display("**> failedtoinit002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> failedtoinit002a: checked class unloaded!"); + log.display("**> failedtoinit002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> failedtoinit002a: waiting for \"quit\" signal..."); + log.display("**> failedtoinit002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> failedtoinit002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> failedtoinit002a: completed!"); + log.display("**> failedtoinit002a: \"quit\" signal recieved!"); + log.display("**> failedtoinit002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> failedtoinit002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001/TestDescription.java index a3fdea994f11..9248927ef618 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001/TestDescription.java @@ -50,7 +50,6 @@ * nsk.jdi.ReferenceType.fieldByName.fieldbyname001a * @run driver * nsk.jdi.ReferenceType.fieldByName.fieldbyname001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001a.java index a08cb86538ab..fa24fc7b8657 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the fieldbyname001 JDI test. */ public class fieldbyname001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i fieldbyname001a: debugee started!"); + log.display("**> fieldbyname001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); fieldbyname001aClassForCheck class_for_check = new fieldbyname001aClassForCheck(); - print_log_on_verbose("**> fieldbyname001a: waiting for \"quit\" signal..."); + log.display("**> fieldbyname001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fieldbyname001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fieldbyname001a: completed succesfully!"); + log.display("**> fieldbyname001a: \"quit\" signal recieved!"); + log.display("**> fieldbyname001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fieldbyname001a: unexpected signal (no \"quit\") - " + instruction); @@ -158,5 +142,4 @@ interface fieldbyname001aInterfaceForCheck { static final long ambiguous_prim_field = 1; static final Object ambiguous_ref_field = new Object(); - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002.java index 7721afec2a2a..6623f9eeea47 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002.java @@ -103,11 +103,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/fieldByName/fieldbyname002 test LOG:"); print_log_on_verbose("==> test checks fieldByName(...) method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002/TestDescription.java index f945b8d74de0..83f0e9a92c24 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.fieldByName.fieldbyname002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002a.java index 84d51fc58f2d..40554b2e53c6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the fieldbyname002 JDI test. */ public class fieldbyname002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.fieldByName."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "fieldbyname002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i fieldbyname002a: debugee started!"); + log.display("**> fieldbyname002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { fieldbyname002aClassLoader customClassLoader = new fieldbyname002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> fieldbyname002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> fieldbyname002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> fieldbyname002a: checked class NOT loaded: " + e); + log.display("--> fieldbyname002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> fieldbyname002a: waiting for \"quit\" signal..."); + log.display("**> fieldbyname002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fieldbyname002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fieldbyname002a: completed succesfully!"); + log.display("**> fieldbyname002a: \"quit\" signal recieved!"); + log.display("**> fieldbyname002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fieldbyname002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java index fa5104cad552..b539d5528f07 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.fieldByName.fieldbyname003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003a.java index 8d2cb87f239b..a2ccc80a72a7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fieldByName/fieldbyname003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the fieldbyname003 JDI test. */ public class fieldbyname003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); static String package_prefix = "nsk.jdi.ReferenceType.fieldByName."; static String checked_class_name = package_prefix + "fieldbyname003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> fieldbyname003a: debugee started!"); + log.display("**> fieldbyname003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> fieldbyname003a: waiting for \"checked class dir\" info..."); + log.display("**> fieldbyname003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -65,23 +56,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> fieldbyname003a: checked class loaded:" + checked_class_name); + log.display("--> fieldbyname003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> fieldbyname003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> fieldbyname003a: checked class NOT loaded:" + checked_class_name); + log.display("--> fieldbyname003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> fieldbyname003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> fieldbyname003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fieldbyname003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fieldbyname003a: completed!"); + log.display("**> fieldbyname003a: \"quit\" signal recieved!"); + log.display("**> fieldbyname003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -91,24 +80,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> fieldbyname003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> fieldbyname003a: enforce to unload checked class..."); + log.display("**> fieldbyname003a: \"continue\" signal recieved!"); + log.display("**> fieldbyname003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> fieldbyname003a: checked class may be NOT unloaded!"); + log.display("**> fieldbyname003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> fieldbyname003a: checked class unloaded!"); + log.display("**> fieldbyname003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> fieldbyname003a: waiting for \"quit\" signal..."); + log.display("**> fieldbyname003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fieldbyname003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fieldbyname003a: completed!"); + log.display("**> fieldbyname003a: \"quit\" signal recieved!"); + log.display("**> fieldbyname003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fieldbyname003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001/TestDescription.java index 45a46baa6f87..14489fd9ce7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.fields.fields001a * @run driver * nsk.jdi.ReferenceType.fields.fields001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001a.java index d72fb7c51249..6c0d4e2ca2e5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the fields001 JDI test. */ public class fields001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i fields001a: debugee started!"); + log.display("**> fields001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); fields001aClassForCheck class_for_check = new fields001aClassForCheck(); - print_log_on_verbose("**> fields001a: waiting for \"quit\" signal..."); + log.display("**> fields001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fields001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fields001a: completed succesfully!"); + log.display("**> fields001a: \"quit\" signal recieved!"); + log.display("**> fields001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fields001a: unexpected signal (no \"quit\") - " + instruction); @@ -158,5 +142,4 @@ interface fields001aInterfaceForCheck { static final long ambiguous_prim_field = 1; static final Object ambiguous_ref_field = new Object(); - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002.java index 3c55e8036359..fd064d1bbe62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,6 @@ public class fields002 { static ArgumentHandler argsHandler; static Log test_log_handler; - static boolean verbose_mode = false; // test argument -verbose switches to true - // - for more easy failure evaluation /** The main class names of the debugger & debugee applications. */ private final static String @@ -55,7 +53,6 @@ public class fields002 { private final static String classLoaderName = package_prefix + "fields002aClassLoader"; private final static String classFieldName = "loadedClass"; - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -72,22 +69,14 @@ public static int run (String argv[], PrintStream out) { int v_test_result = new fields002().runThis(argv,out); if ( v_test_result == 2/*STATUS_FAILED*/ ) { - print_log_anyway("\n==> nsk/jdi/ReferenceType/fields/fields002 test FAILED"); + test_log_handler.complain("\n==> nsk/jdi/ReferenceType/fields/fields002 test FAILED"); } else { - print_log_on_verbose("\n==> nsk/jdi/ReferenceType/fields/fields002 test PASSED"); + test_log_handler.display("\n==> nsk/jdi/ReferenceType/fields/fields002 test PASSED"); } return v_test_result; } - private static void print_log_on_verbose(String message) { - test_log_handler.display(message); - } - - private static void print_log_anyway(String message) { - test_log_handler.complain(message); - } - /** * Non-static variant of the method run(args,out) */ @@ -97,40 +86,33 @@ private int runThis (String argv[], PrintStream out) { test_log_handler = new Log(out, argsHandler); Binder binder = new Binder(argsHandler, test_log_handler); - print_log_on_verbose("==> nsk/jdi/ReferenceType/fields/fields002 test LOG:"); - print_log_on_verbose("==> test checks fields() method of ReferenceType interface "); - print_log_on_verbose(" of the com.sun.jdi package for not prepared class\n"); + test_log_handler.display("==> nsk/jdi/ReferenceType/fields/fields002 test LOG:"); + test_log_handler.display("==> test checks fields() method of ReferenceType interface "); + test_log_handler.display(" of the com.sun.jdi package for not prepared class\n"); String debugee_launch_command = debugeeName; - if (verbose_mode) { - debugee_launch_command = debugeeName + " -vbs"; - } Debugee debugee = binder.bindToDebugee(debugee_launch_command); IOPipe pipe = new IOPipe(debugee); - debugee.redirectStderr(out); - print_log_on_verbose("--> fields002: fields002a debugee launched"); + test_log_handler.display("--> fields002: fields002a debugee launched"); debugee.resume(); String line = pipe.readln(); if (line == null) { - print_log_anyway - ("##> fields002: UNEXPECTED debugee's signal (not \"ready\") - " + line); + test_log_handler.complain("##> fields002: UNEXPECTED debugee's signal (not \"ready\") - " + line); return 2/*STATUS_FAILED*/; } if (!line.equals("ready")) { - print_log_anyway - ("##> fields002: UNEXPECTED debugee's signal (not \"ready\") - " + line); + test_log_handler.complain("##> fields002: UNEXPECTED debugee's signal (not \"ready\") - " + line); return 2/*STATUS_FAILED*/; } else { - print_log_on_verbose("--> fields002: debugee's \"ready\" signal recieved!"); + test_log_handler.display("--> fields002: debugee's \"ready\" signal recieved!"); } - print_log_on_verbose - ("--> fields002: check ReferenceType.fields() method for not prepared " + test_log_handler.display("--> fields002: check ReferenceType.fields() method for not prepared " + class_for_check + " class..."); boolean class_not_found_error = false; boolean fields_method_error = false; @@ -138,7 +120,7 @@ private int runThis (String argv[], PrintStream out) { while ( true ) { // test body ReferenceType loaderRefType = debugee.classByName(classLoaderName); if (loaderRefType == null) { - print_log_anyway("##> Could NOT FIND custom class loader: " + classLoaderName); + test_log_handler.complain("##> Could NOT FIND custom class loader: " + classLoaderName); class_not_found_error = true; break; } @@ -150,7 +132,7 @@ private int runThis (String argv[], PrintStream out) { try { classObjRef = (ClassObjectReference)classValue; } catch (Exception e) { - print_log_anyway ("##> Unexpected exception while getting ClassObjectReference : " + e); + test_log_handler.complain("##> Unexpected exception while getting ClassObjectReference : " + e); class_not_found_error = true; break; } @@ -158,34 +140,27 @@ private int runThis (String argv[], PrintStream out) { ReferenceType refType = classObjRef.reflectedType(); boolean isPrep = refType.isPrepared(); if (isPrep) { - print_log_anyway - ("##> fields002: FAILED: isPrepared() returns for " + class_for_check + " : " + isPrep); + test_log_handler.complain("##> fields002: FAILED: isPrepared() returns for " + class_for_check + " : " + isPrep); class_not_found_error = true; break; } else { - print_log_on_verbose - ("--> fields002: isPrepared() returns for " + class_for_check + " : " + isPrep); + test_log_handler.display("--> fields002: isPrepared() returns for " + class_for_check + " : " + isPrep); } List fields_list = null; try { fields_list = refType.fields(); - print_log_anyway - ("##> fields002: FAILED: NO any Exception thrown!"); - print_log_anyway - ("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); + test_log_handler.complain("##> fields002: FAILED: NO any Exception thrown!"); + test_log_handler.complain("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); fields_method_error = true; } catch (Exception expt) { if (expt instanceof com.sun.jdi.ClassNotPreparedException) { - print_log_on_verbose - ("--> fields002: PASSED: expected Exception thrown - " + expt.toString()); + test_log_handler.display("--> fields002: PASSED: expected Exception thrown - " + expt.toString()); } else { - print_log_anyway - ("##> fields002: FAILED: unexpected Exception thrown - " + expt.toString()); - print_log_anyway - ("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); + test_log_handler.complain("##> fields002: FAILED: unexpected Exception thrown - " + expt.toString()); + test_log_handler.complain("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); fields_method_error = true; } } @@ -196,19 +171,17 @@ private int runThis (String argv[], PrintStream out) { v_test_result = 2/*STATUS_FAILED*/; } - print_log_on_verbose("--> fields002: waiting for debugee finish..."); + test_log_handler.display("--> fields002: waiting for debugee finish..."); pipe.println("quit"); debugee.waitFor(); int status = debugee.getStatus(); if (status != 0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/) { - print_log_anyway - ("##> fields002: UNEXPECTED Debugee's exit status (not 95) - " + status); + test_log_handler.complain("##> fields002: UNEXPECTED Debugee's exit status (not 95) - " + status); v_test_result = 2/*STATUS_FAILED*/; } else { - print_log_on_verbose - ("--> fields002: expected Debugee's exit status - " + status); + test_log_handler.display("--> fields002: expected Debugee's exit status - " + status); } return v_test_result; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002/TestDescription.java index 5bd713a13649..aff66a05f620 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.fields.fields002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002a.java index 5f0501c794e8..0b76dd34241f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the fields002 JDI test. */ public class fields002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.fields."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "fields002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i fields002a: debugee started!"); + log.display("**> fields002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { fields002aClassLoader customClassLoader = new fields002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> fields002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> fields002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> fields002a: checked class NOT loaded: " + e); + log.display("--> fields002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> fields002a: waiting for \"quit\" signal..."); + log.display("**> fields002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fields002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fields002a: completed succesfully!"); + log.display("**> fields002a: \"quit\" signal recieved!"); + log.display("**> fields002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fields002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java index ab6af3a98e15..1ec4980a2cab 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.fields.fields003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003a.java index f808a0577992..cb710ab4ef8b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the fields003 JDI test. */ public class fields003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private static final String package_prefix = "nsk.jdi.ReferenceType.fields."; private static final String checked_class_name = package_prefix + "fields003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> fields003a: debugee started!"); + log.display("**> fields003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> fields003a: waiting for \"checked class dir\" info..."); + log.display("**> fields003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> fields003a: checked class loaded:" + checked_class_name); + log.display("--> fields003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> fields003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> fields003a: checked class NOT loaded:" + checked_class_name); + log.display("--> fields003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> fields003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> fields003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fields003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fields003a: completed!"); + log.display("**> fields003a: \"quit\" signal recieved!"); + log.display("**> fields003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> fields003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> fields003a: enforce to unload checked class..."); + log.display("**> fields003a: \"continue\" signal recieved!"); + log.display("**> fields003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> fields003a: checked class may be NOT unloaded!"); + log.display("**> fields003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> fields003a: checked class unloaded!"); + log.display("**> fields003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> fields003a: waiting for \"quit\" signal..."); + log.display("**> fields003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fields003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fields003a: completed!"); + log.display("**> fields003a: \"quit\" signal recieved!"); + log.display("**> fields003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> fields003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004/TestDescription.java index 7eb5fbd7e38e..492954757b3a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.fields.fields004a * @run driver * nsk.jdi.ReferenceType.fields.fields004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004a.java index 9dc8565cfe41..b8c971b87760 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/fields/fields004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the fields004 JDI test. */ public class fields004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i fields004a: debugee started!"); + log.display("**> fields004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); fields004aClassForCheck class_for_check = new fields004aClassForCheck(); - print_log_on_verbose("**> fields004a: waiting for \"quit\" signal..."); + log.display("**> fields004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> fields004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> fields004a: completed succesfully!"); + log.display("**> fields004a: \"quit\" signal recieved!"); + log.display("**> fields004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> fields004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001/TestDescription.java index 51a6f77a27db..606814297a9d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.hashCode.hashcode001a * @run driver * nsk.jdi.ReferenceType.hashCode.hashcode001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001a.java index 723035860f7f..7021b1674155 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,16 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the hashcode001 JDI test. */ public class hashcode001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -75,33 +72,20 @@ static class s_interf_impl implements s_interf {} InterfaceForCheck_impl interf_for_check_impl0 = new InterfaceForCheck_impl(); InterfaceForCheck interf_for_check0,interf_for_check1[]={interf_for_check0}, interf_for_check2[][]={interf_for_check1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i hashcode001a: debugee started!"); + log.display("**> hashcode001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); hashcode001a hashcode001a_obj = new hashcode001a(); - print_log_on_verbose("**> hashcode001a: waiting for \"quit\" signal..."); + log.display("**> hashcode001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> hashcode001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> hashcode001a: completed succesfully!"); + log.display("**> hashcode001a: \"quit\" signal recieved!"); + log.display("**> hashcode001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> hashcode001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java index 693171c9dfe1..e414117c3ba7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.hashCode.hashcode002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002a.java index f72a629b8a87..bd290d3e0e38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/hashCode/hashcode002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the hashcode002 JDI test. */ public class hashcode002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.hashCode."; private final static String checked_class_name = package_prefix + "hashcode002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> hashcode002a: debugee started!"); + log.display("**> hashcode002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> hashcode002a: waiting for \"checked class dir\" info..."); + log.display("**> hashcode002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> hashcode002a: checked class loaded: " + checked_class_name); + log.display("--> hashcode002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> hashcode002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> hashcode002a: checked class NOT loaded: " + checked_class_name); + log.display("--> hashcode002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> hashcode002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> hashcode002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> hashcode002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> hashcode002a: completed!"); + log.display("**> hashcode002a: \"quit\" signal recieved!"); + log.display("**> hashcode002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> hashcode002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> hashcode002a: enforce to unload checked class..."); + log.display("**> hashcode002a: \"continue\" signal recieved!"); + log.display("**> hashcode002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> hashcode002a: checked class may be NOT unloaded!"); + log.display("**> hashcode002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> hashcode002a: checked class unloaded!"); + log.display("**> hashcode002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> hashcode002a: waiting for \"quit\" signal..."); + log.display("**> hashcode002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> hashcode002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> hashcode002a: completed!"); + log.display("**> hashcode002a: \"quit\" signal recieved!"); + log.display("**> hashcode002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> hashcode002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001/TestDescription.java index 2bd3e7615d11..1492064dfe6a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001/TestDescription.java @@ -43,7 +43,6 @@ * nsk.jdi.ReferenceType.isAbstract.isAbstract001a * @run driver * nsk.jdi.ReferenceType.isAbstract.isAbstract001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001a.java index 464162b9edba..c8897cdadc49 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isAbstract001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isAbstract001 JDI test. */ public class isAbstract001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); // Abstract classes must be extended by a class and that class must be // initialized, so that abstract classes could be returnedin debugger @@ -61,31 +60,18 @@ static class s_interf_impl implements s_interf {} abstr_interf abstr_interf_0, abstr_interf_1[]={abstr_interf_0}; abstr_interf_impl abstr_interf_impl_0= new abstr_interf_impl(); - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isAbstract001a: debugee started!"); + log.display("**> isAbstract001a: debugee started!"); isAbstract001a isAbstract001a_obj = new isAbstract001a(); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isAbstract001a: waiting for \"quit\" signal..."); + log.display("**> isAbstract001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isAbstract001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isAbstract001a: completed succesfully!"); + log.display("**> isAbstract001a: \"quit\" signal recieved!"); + log.display("**> isAbstract001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isAbstract001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java index b61c14d3d4b0..5e030c62b952 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.isAbstract.isabstract002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002a.java index af85baf3d4d7..bb0702047e8b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isAbstract/isabstract002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isabstract002 JDI test. */ public class isabstract002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.isAbstract."; static String checked_class_name = package_prefix + "isabstract002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> isabstract002a: debugee started!"); + log.display("**> isabstract002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isabstract002a: waiting for \"checked class dir\" info..."); + log.display("**> isabstract002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> isabstract002a: checked class loaded: " + checked_class_name); + log.display("--> isabstract002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> isabstract002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> isabstract002a: checked class NOT loaded: " + checked_class_name); + log.display("--> isabstract002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> isabstract002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> isabstract002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isabstract002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isabstract002a: completed!"); + log.display("**> isabstract002a: \"quit\" signal recieved!"); + log.display("**> isabstract002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> isabstract002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> isabstract002a: enforce to unload checked class..."); + log.display("**> isabstract002a: \"continue\" signal recieved!"); + log.display("**> isabstract002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> isabstract002a: checked class may be NOT unloaded!"); + log.display("**> isabstract002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> isabstract002a: checked class unloaded!"); + log.display("**> isabstract002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> isabstract002a: waiting for \"quit\" signal..."); + log.display("**> isabstract002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isabstract002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isabstract002a: completed!"); + log.display("**> isabstract002a: \"quit\" signal recieved!"); + log.display("**> isabstract002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isabstract002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java index 2046927d21ca..163479948b3b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001.java @@ -64,7 +64,6 @@ public class isinit001 { }; - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -111,14 +110,10 @@ private int runThis (String argv[], PrintStream out) { print_log_on_verbose(" of the com.sun.jdi package for ClassType, InterfaceType\n"); String debugee_launch_command = debugeeName; - if (verbose_mode) { - debugee_launch_command = debugeeName + " -vbs"; - } Debugee debugee = binder.bindToDebugee(debugee_launch_command); IOPipe pipe = new IOPipe(debugee); - debugee.redirectStderr(out); print_log_on_verbose("--> isinit001: isinit001a debugee launched"); debugee.resume(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001/TestDescription.java index b19a10c05b0d..7cc984c13002 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001/TestDescription.java @@ -54,7 +54,6 @@ * nsk.jdi.ReferenceType.isInitialized.isinit001a * @run driver * nsk.jdi.ReferenceType.isInitialized.isinit001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001a.java index 91b035ccc293..a4350139b90f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isinit001 JDI test. */ public class isinit001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); NotInitializedClass not_initialized_class_0, not_initialized_class_1[] = {not_initialized_class_0}; @@ -47,33 +45,20 @@ public class isinit001a { int copy_super_class_int_var = SubClass.super_class_int_var; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isinit001a: debugee started!"); + log.display("**> isinit001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); isinit001a isinit001a_obj = new isinit001a(); - print_log_on_verbose("**> isinit001a: waiting for \"quit\" signal..."); + log.display("**> isinit001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isinit001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isinit001a: completed succesfully!"); + log.display("**> isinit001a: \"quit\" signal recieved!"); + log.display("**> isinit001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isinit001a: unexpected signal (no \"quit\") - " + instruction); @@ -88,7 +73,6 @@ class NotInitializedClass {} // not initialized interface interface NotInitializedInterface {} - // initialized interface interface InitializedInterface { static final int int_var = 1; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java index c2b1eac7c1ec..869b47a0eebb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.isInitialized.isinit002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002a.java index 80a766dc2ce1..b96af71248f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isInitialized/isinit002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isinit002 JDI test. */ public class isinit002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.isInitialized."; private final static String checked_class_name = package_prefix + "isinit002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> isinit002a: debugee started!"); + log.display("**> isinit002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isinit002a: waiting for \"checked class dir\" info..."); + log.display("**> isinit002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,20 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> isinit002a: checked class loaded: " + checked_class_name); + log.display("--> isinit002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException - print_log_on_verbose - ("**> isinit002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> isinit002a: checked class NOT loaded: " + checked_class_name); + log.display("**> isinit002a: load class: exception thrown = " + e.toString()); + log.display("--> isinit002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> isinit002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> isinit002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isinit002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isinit002a: completed!"); + log.display("**> isinit002a: \"quit\" signal recieved!"); + log.display("**> isinit002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +78,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> isinit002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> isinit002a: enforce to unload checked class..."); + log.display("**> isinit002a: \"continue\" signal recieved!"); + log.display("**> isinit002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> isinit002a: checked class may be NOT unloaded!"); + log.display("**> isinit002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> isinit002a: checked class unloaded!"); + log.display("**> isinit002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> isinit002a: waiting for \"quit\" signal..."); + log.display("**> isinit002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isinit002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isinit002a: completed!"); + log.display("**> isinit002a: \"quit\" signal recieved!"); + log.display("**> isinit002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isinit002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java index 5b98a1ee949d..d7e22d3674f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001.java @@ -63,7 +63,6 @@ public class isprepared001 { }; - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -110,9 +109,6 @@ private int runThis (String argv[], PrintStream out) { print_log_on_verbose(" of the com.sun.jdi package for ClassType, InterfaceType\n"); String debugee_launch_command = debugeeName; - if (verbose_mode) { - debugee_launch_command = debugeeName + " -vbs"; - } Debugee debugee = binder.bindToDebugee(debugee_launch_command); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001/TestDescription.java index 343b9b1ae24a..853c68bf9d0d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001/TestDescription.java @@ -54,7 +54,6 @@ * nsk.jdi.ReferenceType.isPrepared.isprepared001a * @run driver * nsk.jdi.ReferenceType.isPrepared.isprepared001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001a.java index c43f9ae033cf..4f7c5d488352 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isprepared001 JDI test. */ public class isprepared001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); NotPreparedClass not_prepared_class_0, not_prepared_class_1[] = {not_prepared_class_0}; @@ -43,33 +41,20 @@ public class isprepared001a { PreparedClass prepared_class_0 = new PreparedClass(); - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isprepared001a: debugee started!"); + log.display("**> isprepared001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); isprepared001a isprepared001a_obj = new isprepared001a(); - print_log_on_verbose("**> isprepared001a: waiting for \"quit\" signal..."); + log.display("**> isprepared001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isprepared001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isprepared001a: completed succesfully!"); + log.display("**> isprepared001a: \"quit\" signal recieved!"); + log.display("**> isprepared001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isprepared001a: unexpected signal (no \"quit\") - " + instruction); @@ -84,7 +69,6 @@ class NotPreparedClass {} // not prepared interface interface NotPreparedInterface {} - // prepared interface interface PreparedInterface { static final int int_var = 1; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java index 9030c57a7270..3de35d5943e1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.isPrepared.isprepared002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002a.java index b005131cc4c6..2886c04cbf82 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isPrepared/isprepared002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isprepared002 JDI test. */ public class isprepared002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.isPrepared."; private final static String checked_class_name = package_prefix + "isprepared002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> isprepared002a: debugee started!"); + log.display("**> isprepared002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isprepared002a: waiting for \"checked class dir\" info..."); + log.display("**> isprepared002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> isprepared002a: checked class loaded: " + checked_class_name); + log.display("--> isprepared002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> isprepared002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> isprepared002a: checked class NOT loaded: " + checked_class_name); + log.display("--> isprepared002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> isprepared002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> isprepared002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isprepared002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isprepared002a: completed!"); + log.display("**> isprepared002a: \"quit\" signal recieved!"); + log.display("**> isprepared002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> isprepared002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> isprepared002a: enforce to unload checked class..."); + log.display("**> isprepared002a: \"continue\" signal recieved!"); + log.display("**> isprepared002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> isprepared002a: checked class may be NOT unloaded!"); + log.display("**> isprepared002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> isprepared002a: checked class unloaded!"); + log.display("**> isprepared002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> isprepared002a: waiting for \"quit\" signal..."); + log.display("**> isprepared002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isprepared002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isprepared002a: completed!"); + log.display("**> isprepared002a: \"quit\" signal recieved!"); + log.display("**> isprepared002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isprepared002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001.java index 94b2bba78b2c..689152ad2b5a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001.java @@ -48,7 +48,6 @@ public class isVerified001 { thisClassName = package_prefix + "isVerified001", debugeeName = thisClassName + "a"; - static ArgumentHandler argsHandler; private static Log logHandler; @@ -70,7 +69,6 @@ public class isVerified001 { }; - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -114,14 +112,10 @@ private int runThis (String argv[], PrintStream out) { print_log_on_verbose(" of the com.sun.jdi package for ClassType, InterfaceType\n"); String debugee_launch_command = debugeeName; - if (verbose_mode) { - debugee_launch_command = debugeeName + " -vbs"; - } Debugee debugee = binder.bindToDebugee(debugee_launch_command); IOPipe pipe = new IOPipe(debugee); - debugee.redirectStderr(out); print_log_on_verbose("--> isVerified001: isVerified001a debugee launched"); debugee.resume(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001/TestDescription.java index 9b2dce7f47da..7bc6b3979c48 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001/TestDescription.java @@ -49,7 +49,6 @@ * nsk.jdi.ReferenceType.isVerified.isVerified001a * @run driver * nsk.jdi.ReferenceType.isVerified.isVerified001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001a.java index 4f4649dd0339..bb742cf4166c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isVerified001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isVerified001 JDI test. */ public class isVerified001a { - static boolean verbose_mode = false; + private static Log log = new Log(System.err); isVerified001 a001_0 = new isVerified001(); @@ -46,33 +45,20 @@ public class isVerified001a { verif_subcl verif_subcl_0 = new verif_subcl(); - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i isVerified001a: debugee started!"); + log.display("**> isVerified001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); isVerified001a isVerified001a_obj = new isVerified001a(); - print_log_on_verbose("**> isVerified001a: waiting for \"quit\" signal..."); + log.display("**> isVerified001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isVerified001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isVerified001a: completed succesfully!"); + log.display("**> isVerified001a: \"quit\" signal recieved!"); + log.display("**> isVerified001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isVerified001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java index a766e7476f61..8d5f66835ae2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002/TestDescription.java @@ -64,7 +64,6 @@ * * @run driver * nsk.jdi.ReferenceType.isVerified.isverified002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002a.java index 6a769b9c78bc..0ffd9fdc0922 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isVerified/isverified002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,59 +29,47 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the isverified002 JDI test. */ public class isverified002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); static String package_prefix = "nsk.jdi.ReferenceType.isVerified."; static String checked_class_name = package_prefix + "isverified002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> isverified002a: debugee started!"); + log.display("**> isverified002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> isverified002a: waiting for \"checked class dir\" info..."); + log.display("**> isverified002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; - ClassUnloader classUnloader = new ClassUnloader(); try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> isverified002a: checked class loaded: " + checked_class_name); + log.display("--> isverified002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> isverified002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> isverified002a: checked class NOT loaded: " + checked_class_name); + log.display("--> isverified002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> isverified002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> isverified002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isverified002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isverified002a: completed!"); + log.display("**> isverified002a: \"quit\" signal recieved!"); + log.display("**> isverified002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -91,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> isverified002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> isverified002a: enforce to unload checked class..."); + log.display("**> isverified002a: \"continue\" signal recieved!"); + log.display("**> isverified002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> isverified002a: checked class may be NOT unloaded!"); + log.display("**> isverified002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> isverified002a: checked class unloaded!"); + log.display("**> isverified002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> isverified002a: waiting for \"quit\" signal..."); + log.display("**> isverified002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> isverified002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> isverified002a: completed!"); + log.display("**> isverified002a: \"quit\" signal recieved!"); + log.display("**> isverified002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> isverified002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001/TestDescription.java index 84fa7f432942..663bed874885 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.methods.methods001a * @run driver * nsk.jdi.ReferenceType.methods.methods001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001a.java index 1055d9f06079..12b8313c3046 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methods001 JDI test. */ public class methods001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.methods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methods001aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methods001a: debugee started!"); + log.display("**> methods001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, methods001a.class.getClassLoader()); - print_log_on_verbose - ("--> methods001a: checked class loaded:" + checked_class_name); + log.display("--> methods001a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> methods001a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> methods001a: checked class NOT loaded: " + checked_class_name); + log.display("--> methods001a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methods001a: waiting for \"quit\" signal..."); + log.display("**> methods001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methods001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methods001a: completed succesfully!"); + log.display("**> methods001a: \"quit\" signal recieved!"); + log.display("**> methods001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methods001a: unexpected signal (no \"quit\") - " + instruction); @@ -197,7 +180,6 @@ public void i_interf_overridden_void_par_method(int i) {} // static initializer static {} - } abstract class methods001aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002.java index b54e423eb70f..7569f5918825 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,6 @@ public class methods002 { static ArgumentHandler argsHandler; static Log test_log_handler; - static boolean verbose_mode = false; // test argument -verbose switches to true - // - for more easy failure evaluation /** The main class names of the debugger & debugee applications. */ private final static String @@ -55,7 +53,6 @@ public class methods002 { private final static String classLoaderName = package_prefix + "methods002aClassLoader"; private final static String classFieldName = "loadedClass"; - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -72,22 +69,14 @@ public static int run (String argv[], PrintStream out) { int v_test_result = new methods002().runThis(argv,out); if ( v_test_result == 2/*STATUS_FAILED*/ ) { - print_log_anyway("\n==> nsk/jdi/ReferenceType/methods/methods002 test FAILED"); + test_log_handler.complain("\n==> nsk/jdi/ReferenceType/methods/methods002 test FAILED"); } else { - print_log_on_verbose("\n==> nsk/jdi/ReferenceType/methods/methods002 test PASSED"); + test_log_handler.display("\n==> nsk/jdi/ReferenceType/methods/methods002 test PASSED"); } return v_test_result; } - private static void print_log_on_verbose(String message) { - test_log_handler.display(message); - } - - private static void print_log_anyway(String message) { - test_log_handler.complain(message); - } - /** * Non-static variant of the method run(args,out) */ @@ -97,40 +86,33 @@ private int runThis (String argv[], PrintStream out) { test_log_handler = new Log(out, argsHandler); Binder binder = new Binder(argsHandler, test_log_handler); - print_log_on_verbose("==> nsk/jdi/ReferenceType/methods/methods002 test LOG:"); - print_log_on_verbose("==> test checks methods() method of ReferenceType interface "); - print_log_on_verbose(" of the com.sun.jdi package for not prepared class\n"); + test_log_handler.display("==> nsk/jdi/ReferenceType/methods/methods002 test LOG:"); + test_log_handler.display("==> test checks methods() method of ReferenceType interface "); + test_log_handler.display(" of the com.sun.jdi package for not prepared class\n"); String debugee_launch_command = debugeeName; - if (verbose_mode) { - debugee_launch_command = debugeeName + " -vbs"; - } Debugee debugee = binder.bindToDebugee(debugee_launch_command); IOPipe pipe = new IOPipe(debugee); - debugee.redirectStderr(out); - print_log_on_verbose("--> methods002: methods002a debugee launched"); + test_log_handler.display("--> methods002: methods002a debugee launched"); debugee.resume(); String line = pipe.readln(); if (line == null) { - print_log_anyway - ("##> methods002: UNEXPECTED debugee's signal (not \"ready\") - " + line); + test_log_handler.complain("##> methods002: UNEXPECTED debugee's signal (not \"ready\") - " + line); return 2/*STATUS_FAILED*/; } if (!line.equals("ready")) { - print_log_anyway - ("##> methods002: UNEXPECTED debugee's signal (not \"ready\") - " + line); + test_log_handler.complain("##> methods002: UNEXPECTED debugee's signal (not \"ready\") - " + line); return 2/*STATUS_FAILED*/; } else { - print_log_on_verbose("--> methods002: debugee's \"ready\" signal recieved!"); + test_log_handler.display("--> methods002: debugee's \"ready\" signal recieved!"); } - print_log_on_verbose - ("--> methods002: check ReferenceType.methods() method for not prepared " + test_log_handler.display("--> methods002: check ReferenceType.methods() method for not prepared " + class_for_check + " class..."); boolean class_not_found_error = false; boolean methods_method_error = false; @@ -138,7 +120,7 @@ private int runThis (String argv[], PrintStream out) { while ( true ) { // test body ReferenceType loaderRefType = debugee.classByName(classLoaderName); if (loaderRefType == null) { - print_log_anyway("##> Could NOT FIND custom class loader: " + classLoaderName); + test_log_handler.complain("##> Could NOT FIND custom class loader: " + classLoaderName); class_not_found_error = true; break; } @@ -150,7 +132,7 @@ private int runThis (String argv[], PrintStream out) { try { classObjRef = (ClassObjectReference)classValue; } catch (Exception e) { - print_log_anyway ("##> Unexpected exception while getting ClassObjectReference : " + e); + test_log_handler.complain("##> Unexpected exception while getting ClassObjectReference : " + e); class_not_found_error = true; break; } @@ -158,34 +140,27 @@ private int runThis (String argv[], PrintStream out) { ReferenceType refType = classObjRef.reflectedType(); boolean isPrep = refType.isPrepared(); if (isPrep) { - print_log_anyway - ("##> methods002: FAILED: isPrepared() returns for " + class_for_check + " : " + isPrep); + test_log_handler.complain("##> methods002: FAILED: isPrepared() returns for " + class_for_check + " : " + isPrep); class_not_found_error = true; break; } else { - print_log_on_verbose - ("--> methods002: isPrepared() returns for " + class_for_check + " : " + isPrep); + test_log_handler.display("--> methods002: isPrepared() returns for " + class_for_check + " : " + isPrep); } List methods_list = null; try { methods_list = refType.methods(); - print_log_anyway - ("##> methods002: FAILED: NO any Exception thrown!"); - print_log_anyway - ("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); + test_log_handler.complain("##> methods002: FAILED: NO any Exception thrown!"); + test_log_handler.complain("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); methods_method_error = true; } catch (Exception expt) { if (expt instanceof com.sun.jdi.ClassNotPreparedException) { - print_log_on_verbose - ("--> methods002: PASSED: expected Exception thrown - " + expt.toString()); + test_log_handler.display("--> methods002: PASSED: expected Exception thrown - " + expt.toString()); } else { - print_log_anyway - ("##> methods002: FAILED: unexpected Exception thrown - " + expt.toString()); - print_log_anyway - ("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); + test_log_handler.complain("##> methods002: FAILED: unexpected Exception thrown - " + expt.toString()); + test_log_handler.complain("##> expected Exception - com.sun.jdi.ClassNotPreparedException"); methods_method_error = true; } } @@ -196,19 +171,17 @@ private int runThis (String argv[], PrintStream out) { v_test_result = 2/*STATUS_FAILED*/; } - print_log_on_verbose("--> methods002: waiting for debugee finish..."); + test_log_handler.display("--> methods002: waiting for debugee finish..."); pipe.println("quit"); debugee.waitFor(); int status = debugee.getStatus(); if (status != 0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/) { - print_log_anyway - ("##> methods002: UNEXPECTED Debugee's exit status (not 95) - " + status); + test_log_handler.complain("##> methods002: UNEXPECTED Debugee's exit status (not 95) - " + status); v_test_result = 2/*STATUS_FAILED*/; } else { - print_log_on_verbose - ("--> methods002: expected Debugee's exit status - " + status); + test_log_handler.display("--> methods002: expected Debugee's exit status - " + status); } return v_test_result; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002/TestDescription.java index b8957fb1c0ee..c5e211ec5724 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.methods.methods002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002a.java index 8ac4f767fe1c..50c2980102e2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,30 +34,16 @@ public class methods002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methods002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methods002a: debugee started!"); + log.display("**> methods002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -66,19 +52,17 @@ public static void main (String argv[]) { methods002aClassLoader customClassLoader = new methods002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> methods002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> methods002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> methods002a: checked class NOT loaded: " + e); + log.display("--> methods002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> methods002a: waiting for \"quit\" signal..."); + log.display("**> methods002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methods002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methods002a: completed succesfully!"); + log.display("**> methods002a: \"quit\" signal recieved!"); + log.display("**> methods002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methods002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java index 5a37d7e66a4e..f102e1281024 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003/TestDescription.java @@ -61,7 +61,6 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run driver * nsk.jdi.ReferenceType.methods.methods003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003a.java index 0e8c2e3399cb..54a2bbe000b7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methods003 JDI test. */ public class methods003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methods."; private final static String checked_class_name = package_prefix + "methods003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> methods003a: debugee started!"); + log.display("**> methods003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> methods003a: waiting for \"checked class dir\" info..."); + log.display("**> methods003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> methods003a: checked class loaded:" + checked_class_name); + log.display("--> methods003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> methods003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> methods003a: checked class NOT loaded:" + checked_class_name); + log.display("--> methods003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methods003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> methods003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methods003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methods003a: completed!"); + log.display("**> methods003a: \"quit\" signal recieved!"); + log.display("**> methods003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> methods003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> methods003a: enforce to unload checked class..."); + log.display("**> methods003a: \"continue\" signal recieved!"); + log.display("**> methods003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> methods003a: checked class may be NOT unloaded!"); + log.display("**> methods003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> methods003a: checked class unloaded!"); + log.display("**> methods003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> methods003a: waiting for \"quit\" signal..."); + log.display("**> methods003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methods003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methods003a: completed!"); + log.display("**> methods003a: \"quit\" signal recieved!"); + log.display("**> methods003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methods003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004/TestDescription.java index 25778f2f00c3..d6464f4645db 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.methods.methods004a * @run driver * nsk.jdi.ReferenceType.methods.methods004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004a.java index 41c1dec7e5eb..8f3d95cefc7f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methods/methods004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methods004 JDI test. */ public class methods004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i methods004a: debugee started!"); + log.display("**> methods004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); methods004aClassForCheck class_for_check = new methods004aClassForCheck(); - print_log_on_verbose("**> methods004a: waiting for \"quit\" signal..."); + log.display("**> methods004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methods004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methods004a: completed succesfully!"); + log.display("**> methods004a: \"quit\" signal recieved!"); + log.display("**> methods004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> methods004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001/TestDescription.java index 11dd886ea201..a16a9c936d4a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s001a * @run driver * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001a.java index 54290e729455..1fb31279c6f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methbyname_s001 JDI test. */ public class methbyname_s001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_s."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methbyname_s001aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methbyname_s001a: debugee started!"); + log.display("**> methbyname_s001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, methbyname_s001a.class.getClassLoader()); - print_log_on_verbose - ("--> methbyname_s001a: checked class loaded:" + checked_class_name); + log.display("--> methbyname_s001a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> methbyname_s001a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> methbyname_s001a: checked class NOT loaded: " + checked_class_name); + log.display("--> methbyname_s001a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methbyname_s001a: waiting for \"quit\" signal..."); + log.display("**> methbyname_s001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_s001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_s001a: completed succesfully!"); + log.display("**> methbyname_s001a: \"quit\" signal recieved!"); + log.display("**> methbyname_s001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_s001a: unexpected signal (no \"quit\") - " + instruction); @@ -193,11 +176,9 @@ public void i_interf_overridden_void_par_method(int i) {} protected Object i_protected_method(Object obj) {return new Object();} public Object i_public_method(Object obj) {return new Object();} - // static initializer static {} - } abstract class methbyname_s001aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002.java index 57663947dd15..2917004d0977 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002.java @@ -57,8 +57,6 @@ public class methbyname_s002 { static ArgumentHandler argsHandler; private static Log logHandler; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -97,18 +95,13 @@ private void print_log_anyway(String message) { */ private int runThis (String argv[], PrintStream out) { - argsHandler = new ArgumentHandler(argv); logHandler = new Log(out, argsHandler); Binder binder = new Binder(argsHandler, logHandler); Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002 test LOG:"); print_log_on_verbose("==> test checks methodsByName(String name) method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002/TestDescription.java index bdfe397adf30..5563e139b1fe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002a.java index fd2377ccb7d6..2df2a86c6379 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the methbyname_s002 JDI test. */ public class methbyname_s002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_s."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methbyname_s002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methbyname_s002a: debugee started!"); + log.display("**> methbyname_s002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { methbyname_s002aClassLoader customClassLoader = new methbyname_s002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> methbyname_s002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> methbyname_s002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> methbyname_s002a: checked class NOT loaded: " + e); + log.display("--> methbyname_s002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> methbyname_s002a: waiting for \"quit\" signal..."); + log.display("**> methbyname_s002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_s002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_s002a: completed succesfully!"); + log.display("**> methbyname_s002a: \"quit\" signal recieved!"); + log.display("**> methbyname_s002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_s002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java index 6f70f225a147..234d205cca44 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003a.java index 5ef8e69611ed..9ee25a400a21 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methbyname_s003 JDI test. */ public class methbyname_s003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_s."; private final static String checked_class_name = package_prefix + "methbyname_s003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> methbyname_s003a: debugee started!"); + log.display("**> methbyname_s003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> methbyname_s003a: waiting for \"checked class dir\" info..."); + log.display("**> methbyname_s003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> methbyname_s003a: checked class loaded:" + checked_class_name); + log.display("--> methbyname_s003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> methbyname_s003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> methbyname_s003a: checked class NOT loaded:" + checked_class_name); + log.display("--> methbyname_s003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methbyname_s003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> methbyname_s003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_s003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_s003a: completed!"); + log.display("**> methbyname_s003a: \"quit\" signal recieved!"); + log.display("**> methbyname_s003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> methbyname_s003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> methbyname_s003a: enforce to unload checked class..."); + log.display("**> methbyname_s003a: \"continue\" signal recieved!"); + log.display("**> methbyname_s003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> methbyname_s003a: checked class may be NOT unloaded!"); + log.display("**> methbyname_s003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> methbyname_s003a: checked class unloaded!"); + log.display("**> methbyname_s003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> methbyname_s003a: waiting for \"quit\" signal..."); + log.display("**> methbyname_s003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_s003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_s003a: completed!"); + log.display("**> methbyname_s003a: \"quit\" signal recieved!"); + log.display("**> methbyname_s003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_s003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004/TestDescription.java index c0e9a10a0988..c3269eb22957 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s004a * @run driver * nsk.jdi.ReferenceType.methodsByName_s.methbyname_s004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004a.java index 24ea124d6c47..9edec597fea5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_s/methbyname_s004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methbyname_s004 JDI test. */ public class methbyname_s004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_s."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methbyname_s004aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methbyname_s004a: debugee started!"); + log.display("**> methbyname_s004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, methbyname_s004a.class.getClassLoader()); - print_log_on_verbose - ("--> methbyname_s004a: checked class loaded:" + checked_class_name); + log.display("--> methbyname_s004a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> methbyname_s004a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> methbyname_s004a: checked class NOT loaded: " + checked_class_name); + log.display("--> methbyname_s004a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methbyname_s004a: waiting for \"quit\" signal..."); + log.display("**> methbyname_s004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_s004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_s004a: completed succesfully!"); + log.display("**> methbyname_s004a: \"quit\" signal recieved!"); + log.display("**> methbyname_s004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_s004a: unexpected signal (no \"quit\") - " + instruction); @@ -92,7 +75,6 @@ public static void main (String argv[]) { abstract class methbyname_s004aClassForCheck extends methbyname_s004aSuperClassForCheck implements methbyname_s004aInterfaceForCheck { - // overloaded static methods static void s_overloaded_method() {} static String s_overloaded_method(String s) {return "string";} @@ -110,7 +92,6 @@ void i_overloaded_method() {} Object i_super_overloaded_method(long l, String s) {return new Object();} Object i_interf_overloaded_method(long l, String s) {return new Object();} - } abstract class methbyname_s004aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001/TestDescription.java index de09aec27ff7..15d10c0ce975 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss001a * @run driver * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001a.java index 13cfdf259019..a8f1589da711 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methbyname_ss001 JDI test. */ public class methbyname_ss001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_ss."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methbyname_ss001aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methbyname_ss001a: debugee started!"); + log.display("**> methbyname_ss001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, methbyname_ss001a.class.getClassLoader()); - print_log_on_verbose - ("--> methbyname_ss001a: checked class loaded:" + checked_class_name); + log.display("--> methbyname_ss001a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> methbyname_ss001a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> methbyname_ss001a: checked class NOT loaded: " + checked_class_name); + log.display("--> methbyname_ss001a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methbyname_ss001a: waiting for \"quit\" signal..."); + log.display("**> methbyname_ss001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_ss001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_ss001a: completed succesfully!"); + log.display("**> methbyname_ss001a: \"quit\" signal recieved!"); + log.display("**> methbyname_ss001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_ss001a: unexpected signal (no \"quit\") - " + instruction); @@ -194,7 +177,6 @@ public void i_interf_overridden_void_par_method(int i) {} protected Object i_protected_method(Object obj) {return new Object();} public Object i_public_method(Object obj) {return new Object();} - // static initializer static {} @@ -215,7 +197,6 @@ void i_overloaded_method() {} Object i_super_overloaded_method(long l, String s) {return new Object();} Object i_interf_overloaded_method(long l, String s) {return new Object();} - } abstract class methbyname_ss001aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002.java index 4fdd23afb729..6b3b538ff299 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002.java @@ -57,8 +57,6 @@ public class methbyname_ss002 { static ArgumentHandler argsHandler; private static Log logHandler; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -103,11 +101,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002 test LOG:"); print_log_on_verbose("==> test checks methodsByName(String name, String signature) method of ReferenceType "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002/TestDescription.java index 0113bf81f931..632873e59c1c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002a.java index 88dbe5521aec..c207d87c7eb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the methbyname_ss002 JDI test. */ public class methbyname_ss002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_ss."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "methbyname_ss002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i methbyname_ss002a: debugee started!"); + log.display("**> methbyname_ss002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { methbyname_ss002aClassLoader customClassLoader = new methbyname_ss002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> methbyname_ss002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> methbyname_ss002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> methbyname_ss002a: checked class NOT loaded: " + e); + log.display("--> methbyname_ss002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> methbyname_ss002a: waiting for \"quit\" signal..."); + log.display("**> methbyname_ss002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_ss002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_ss002a: completed succesfully!"); + log.display("**> methbyname_ss002a: \"quit\" signal recieved!"); + log.display("**> methbyname_ss002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_ss002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java index baf8931a6364..37e4026d4848 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.methodsByName_ss.methbyname_ss003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003a.java index 57906353d8a5..fa6a940052c9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/methodsByName_ss/methbyname_ss003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the methbyname_ss003 JDI test. */ public class methbyname_ss003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.methodsByName_ss."; private final static String checked_class_name = package_prefix + "methbyname_ss003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> methbyname_ss003a: debugee started!"); + log.display("**> methbyname_ss003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> methbyname_ss003a: waiting for \"checked class dir\" info..."); + log.display("**> methbyname_ss003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> methbyname_ss003a: checked class loaded:" + checked_class_name); + log.display("--> methbyname_ss003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> methbyname_ss003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> methbyname_ss003a: checked class NOT loaded:" + checked_class_name); + log.display("--> methbyname_ss003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> methbyname_ss003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> methbyname_ss003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_ss003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_ss003a: completed!"); + log.display("**> methbyname_ss003a: \"quit\" signal recieved!"); + log.display("**> methbyname_ss003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> methbyname_ss003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> methbyname_ss003a: enforce to unload checked class..."); + log.display("**> methbyname_ss003a: \"continue\" signal recieved!"); + log.display("**> methbyname_ss003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> methbyname_ss003a: checked class may be NOT unloaded!"); + log.display("**> methbyname_ss003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> methbyname_ss003a: checked class unloaded!"); + log.display("**> methbyname_ss003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> methbyname_ss003a: waiting for \"quit\" signal..."); + log.display("**> methbyname_ss003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> methbyname_ss003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> methbyname_ss003a: completed!"); + log.display("**> methbyname_ss003a: \"quit\" signal recieved!"); + log.display("**> methbyname_ss003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> methbyname_ss003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001/TestDescription.java index 77b7eb38ad8e..1fb3839629c0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.name.name001a * @run driver * nsk.jdi.ReferenceType.name.name001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001a.java index 7525f8b96e91..acbb6c6c7724 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,16 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the name001 JDI test. */ public class name001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - + private static Log log = new Log(System.err); boolean z0, z1[]={z0}, z2[][]={z1}; byte b0, b1[]={b0}, b2[][]={b1}; @@ -77,33 +74,20 @@ static class s_interf_impl implements s_interf {} interf_for_check1[]={interf_for_check0}, interf_for_check2[][]={interf_for_check1}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i name001a: debugee started!"); + log.display("**> name001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); name001a name001a_obj = new name001a(); - print_log_on_verbose("**> name001a: waiting for \"quit\" signal..."); + log.display("**> name001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> name001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> name001a: completed succesfully!"); + log.display("**> name001a: \"quit\" signal recieved!"); + log.display("**> name001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> name001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java index 927e07929b48..58475e2de8ba 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.name.name002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002a.java index 385056310fb5..c8f1dac1dbdb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/name/name002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the name002 JDI test. */ public class name002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.name."; private final static String checked_class_name = package_prefix + "name002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> name002a: debugee started!"); + log.display("**> name002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> name002a: waiting for \"checked class dir\" info..."); + log.display("**> name002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> name002a: checked class loaded: " + checked_class_name); + log.display("--> name002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> name002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> name002a: checked class NOT loaded: " + checked_class_name); + log.display("--> name002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> name002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> name002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> name002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> name002a: completed!"); + log.display("**> name002a: \"quit\" signal recieved!"); + log.display("**> name002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> name002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> name002a: enforce to unload checked class..."); + log.display("**> name002a: \"continue\" signal recieved!"); + log.display("**> name002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> name002a: checked class may be NOT unloaded!"); + log.display("**> name002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> name002a: checked class unloaded!"); + log.display("**> name002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> name002a: waiting for \"quit\" signal..."); + log.display("**> name002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> name002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> name002a: completed!"); + log.display("**> name002a: \"quit\" signal recieved!"); + log.display("**> name002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> name002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001/TestDescription.java index 23b6da5bd0a1..cbff28ba6d25 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.sourceName.sourcename001a * @run driver * nsk.jdi.ReferenceType.sourceName.sourcename001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001a.java index b6d6e49b9ce9..e4e10e328b47 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,13 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the sourcename001 JDI test. */ public class sourcename001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); // Classes must be loaded and linked, so all fields must be // initialized @@ -58,33 +56,20 @@ static class s_interf_impl implements s_interf {} sourcename001 sourcename001_0 = new sourcename001(), sourcename001_1[]={sourcename001_0}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i sourcename001a: debugee started!"); + log.display("**> sourcename001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); sourcename001a sourcename001a_obj = new sourcename001a(); - print_log_on_verbose("**> sourcename001a: waiting for \"quit\" signal..."); + log.display("**> sourcename001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> sourcename001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> sourcename001a: completed succesfully!"); + log.display("**> sourcename001a: \"quit\" signal recieved!"); + log.display("**> sourcename001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> sourcename001a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java index 543272a52f0f..b30db9c9c937 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.sourceName.sourcename002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002a.java index dcb2f8ec75f3..57e291a394ad 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the sourcename002 JDI test. */ public class sourcename002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.sourceName."; private final static String checked_class_name = package_prefix + "sourcename002b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> sourcename002a: debugee started!"); + log.display("**> sourcename002a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> sourcename002a: waiting for \"checked class dir\" info..."); + log.display("**> sourcename002a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,20 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> sourcename002a: checked class loaded: " + checked_class_name); + log.display("--> sourcename002a: checked class loaded: " + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException - print_log_on_verbose - ("**> sourcename002a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> sourcename002a: checked class NOT loaded: " + checked_class_name); + log.display("**> sourcename002a: load class: exception thrown = " + e.toString()); + log.display("--> sourcename002a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> sourcename002a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> sourcename002a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> sourcename002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> sourcename002a: completed!"); + log.display("**> sourcename002a: \"quit\" signal recieved!"); + log.display("**> sourcename002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +78,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> sourcename002a: \"continue\" signal recieved!"); - print_log_on_verbose("**> sourcename002a: enforce to unload checked class..."); + log.display("**> sourcename002a: \"continue\" signal recieved!"); + log.display("**> sourcename002a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> sourcename002a: checked class may be NOT unloaded!"); + log.display("**> sourcename002a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> sourcename002a: checked class unloaded!"); + log.display("**> sourcename002a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> sourcename002a: waiting for \"quit\" signal..."); + log.display("**> sourcename002a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> sourcename002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> sourcename002a: completed!"); + log.display("**> sourcename002a: \"quit\" signal recieved!"); + log.display("**> sourcename002a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> sourcename002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003/TestDescription.java index ab5624f9332c..f8b900ef6d92 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003/TestDescription.java @@ -46,7 +46,6 @@ * nsk.jdi.ReferenceType.sourceName.sourcename003a * @run driver * nsk.jdi.ReferenceType.sourceName.sourcename003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003a.java index 3bdeddb3ec3b..f51a76fe342b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/sourceName/sourcename003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,45 +27,30 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the sourcename003 JDI test. */ public class sourcename003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); sourcename003 sourcename003_0, sourcename003_1[]={sourcename003_0}; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i sourcename003a: debugee started!"); + log.display("**> sourcename003a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); sourcename003a sourcename003a_obj = new sourcename003a(); - print_log_on_verbose("**> sourcename003a: waiting for \"quit\" signal..."); + log.display("**> sourcename003a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> sourcename003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> sourcename003a: completed succesfully!"); + log.display("**> sourcename003a: \"quit\" signal recieved!"); + log.display("**> sourcename003a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> sourcename003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001/TestDescription.java index 6e1e570c6c54..3ca6b0382034 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001/TestDescription.java @@ -48,7 +48,6 @@ * nsk.jdi.ReferenceType.visibleFields.visibfield001a * @run driver * nsk.jdi.ReferenceType.visibleFields.visibfield001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001a.java index 208a73ad90ab..8dca099e1d92 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibfield001 JDI test. */ public class visibfield001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i visibfield001a: debugee started!"); + log.display("**> visibfield001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); visibfield001aClassForCheck class_for_check = new visibfield001aClassForCheck(); - print_log_on_verbose("**> visibfield001a: waiting for \"quit\" signal..."); + log.display("**> visibfield001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibfield001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibfield001a: completed succesfully!"); + log.display("**> visibfield001a: \"quit\" signal recieved!"); + log.display("**> visibfield001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibfield001a: unexpected signal (no \"quit\") - " + instruction); @@ -159,5 +143,4 @@ interface visibfield001aInterfaceForCheck { static final long ambiguous_prim_field = 1; static final Object ambiguous_ref_field = new Object(); - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002.java index 1e11aac9eba6..4d067036628c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002.java @@ -57,8 +57,6 @@ public class visibfield002 { static ArgumentHandler argsHandler; private static Log logHandler; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -103,11 +101,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/visibleFields/visibfield002 test LOG:"); print_log_on_verbose("==> test checks visibleFields() method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002/TestDescription.java index fb417aa7a1d9..f469c4431f6a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.visibleFields.visibfield002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002a.java index b8b7ac9f5918..da0845966d5f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the visibfield002 JDI test. */ public class visibfield002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.visibleFields."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "visibfield002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i visibfield002a: debugee started!"); + log.display("**> visibfield002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { visibfield002aClassLoader customClassLoader = new visibfield002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> visibfield002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> visibfield002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> visibfield002a: checked class NOT loaded: " + e); + log.display("--> visibfield002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> visibfield002a: waiting for \"quit\" signal..."); + log.display("**> visibfield002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibfield002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibfield002a: completed succesfully!"); + log.display("**> visibfield002a: \"quit\" signal recieved!"); + log.display("**> visibfield002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibfield002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java index f349deaad85a..fbc145a86e2a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.visibleFields.visibfield003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003a.java index 56be764f85b5..7615bbbe93ed 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibfield003 JDI test. */ public class visibfield003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.visibleFields."; private final static String checked_class_name = package_prefix + "visibfield003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> visibfield003a: debugee started!"); + log.display("**> visibfield003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> visibfield003a: waiting for \"checked class dir\" info..."); + log.display("**> visibfield003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> visibfield003a: checked class loaded:" + checked_class_name); + log.display("--> visibfield003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> visibfield003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> visibfield003a: checked class NOT loaded:" + checked_class_name); + log.display("--> visibfield003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> visibfield003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> visibfield003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibfield003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibfield003a: completed!"); + log.display("**> visibfield003a: \"quit\" signal recieved!"); + log.display("**> visibfield003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> visibfield003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> visibfield003a: enforce to unload checked class..."); + log.display("**> visibfield003a: \"continue\" signal recieved!"); + log.display("**> visibfield003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> visibfield003a: checked class may be NOT unloaded!"); + log.display("**> visibfield003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> visibfield003a: checked class unloaded!"); + log.display("**> visibfield003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> visibfield003a: waiting for \"quit\" signal..."); + log.display("**> visibfield003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibfield003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibfield003a: completed!"); + log.display("**> visibfield003a: \"quit\" signal recieved!"); + log.display("**> visibfield003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibfield003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004/TestDescription.java index 5f3584cbd91b..bc0f60811143 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.visibleFields.visibfield004a * @run driver * nsk.jdi.ReferenceType.visibleFields.visibfield004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004a.java index acca91d0c439..773f8f7e5ed5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleFields/visibfield004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibfield004 JDI test. */ public class visibfield004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i visibfield004a: debugee started!"); + log.display("**> visibfield004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); visibfield004aClassForCheck class_for_check = new visibfield004aClassForCheck(); - print_log_on_verbose("**> visibfield004a: waiting for \"quit\" signal..."); + log.display("**> visibfield004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibfield004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibfield004a: completed succesfully!"); + log.display("**> visibfield004a: \"quit\" signal recieved!"); + log.display("**> visibfield004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> visibfield004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001/TestDescription.java index 08379613165f..2a1a0de8997f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.visibleMethods.visibmethod001a * @run driver * nsk.jdi.ReferenceType.visibleMethods.visibmethod001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001a.java index 723b65577c77..127263b16375 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibmethod001 JDI test. */ public class visibmethod001a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.visibleMethods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "visibmethod001aClassForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i visibmethod001a: debugee started!"); + log.display("**> visibmethod001a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, visibmethod001a.class.getClassLoader()); - print_log_on_verbose - ("--> visibmethod001a: checked class loaded:" + checked_class_name); + log.display("--> visibmethod001a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> visibmethod001a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> visibmethod001a: checked class NOT loaded: " + checked_class_name); + log.display("--> visibmethod001a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> visibmethod001a: waiting for \"quit\" signal..."); + log.display("**> visibmethod001a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod001a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod001a: completed succesfully!"); + log.display("**> visibmethod001a: \"quit\" signal recieved!"); + log.display("**> visibmethod001a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibmethod001a: unexpected signal (no \"quit\") - " + instruction); @@ -197,7 +180,6 @@ public void i_interf_overridden_void_par_method(int i) {} // static initializer static {} - } abstract class visibmethod001aSuperClassForCheck { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002.java index b8c2d032c315..7ca700382c1c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002.java @@ -57,8 +57,6 @@ public class visibmethod002 { static ArgumentHandler argsHandler; private static Log logHandler; - - public static void main (String argv[]) { int result = run(argv,System.out); if (result != 0) { @@ -103,11 +101,7 @@ private int runThis (String argv[], PrintStream out) { Debugee debugee; - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); - } else { - debugee = binder.bindToDebugee(debugeeName); - } + debugee = binder.bindToDebugee(debugeeName); print_log_on_verbose("==> nsk/jdi/ReferenceType/visibleMethods/visibmethod002 test LOG:"); print_log_on_verbose("==> test checks visibleMethods() method of ReferenceType interface "); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002/TestDescription.java index 72978fd9bc3b..3ac38c675dde 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002/TestDescription.java @@ -56,7 +56,6 @@ * * @run driver * nsk.jdi.ReferenceType.visibleMethods.visibmethod002 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002a.java index 4f219b75cf1c..87e27bb95d24 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,37 +28,22 @@ import nsk.share.jdi.*; import java.io.*; - /** * This class is used as debugee application for the visibmethod002 JDI test. */ public class visibmethod002a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.visibleMethods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "visibmethod002aClassForCheck"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i visibmethod002a: debugee started!"); + log.display("**> visibmethod002a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -67,19 +52,17 @@ public static void main (String argv[]) { visibmethod002aClassLoader customClassLoader = new visibmethod002aClassLoader(checked_class_dir, checked_class_name); try { customClassLoader.preloadClass(checked_class_name); - print_log_on_verbose - ("--> visibmethod002a: checked class loaded but not prepared: " + checked_class_name); + log.display("--> visibmethod002a: checked class loaded but not prepared: " + checked_class_name); } catch (Throwable e) { // ClassNotFoundException - print_log_on_verbose - ("--> visibmethod002a: checked class NOT loaded: " + e); + log.display("--> visibmethod002a: checked class NOT loaded: " + e); } - print_log_on_verbose("**> visibmethod002a: waiting for \"quit\" signal..."); + log.display("**> visibmethod002a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod002a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod002a: completed succesfully!"); + log.display("**> visibmethod002a: \"quit\" signal recieved!"); + log.display("**> visibmethod002a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibmethod002a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java index c6de37e2939f..19afceedbf03 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003/TestDescription.java @@ -62,7 +62,6 @@ * * @run driver * nsk.jdi.ReferenceType.visibleMethods.visibmethod003 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003a.java index b04195f51d30..421cd5780377 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,34 +29,25 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibmethod003 JDI test. */ public class visibmethod003a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); private final static String package_prefix = "nsk.jdi.ReferenceType.visibleMethods."; private final static String checked_class_name = package_prefix + "visibmethod003b"; - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { ArgumentHandler argHandler = new ArgumentHandler(argv); - verbose_mode = argHandler.verbose(); - print_log_on_verbose("**> visibmethod003a: debugee started!"); + log.display("**> visibmethod003a: debugee started!"); IOPipe pipe = argHandler.createDebugeeIOPipe(); - print_log_on_verbose("**> visibmethod003a: waiting for \"checked class dir\" info..."); + log.display("**> visibmethod003a: waiting for \"checked class dir\" info..."); pipe.println("ready0"); String checked_class_dir = (argHandler.getArguments())[0] + File.separator + "loadclass"; @@ -64,23 +55,21 @@ public static void main (String argv[]) { try { classUnloader.loadClass(checked_class_name, checked_class_dir); - print_log_on_verbose - ("--> visibmethod003a: checked class loaded:" + checked_class_name); + log.display("--> visibmethod003a: checked class loaded:" + checked_class_name); } catch ( Exception e ) { // ClassNotFoundException System.err.println ("**> visibmethod003a: load class: exception thrown = " + e.toString()); - print_log_on_verbose - ("--> visibmethod003a: checked class NOT loaded:" + checked_class_name); + log.display("--> visibmethod003a: checked class NOT loaded:" + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> visibmethod003a: waiting for \"continue\" or \"quit\" signal..."); + log.display("**> visibmethod003a: waiting for \"continue\" or \"quit\" signal..."); pipe.println("ready1"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod003a: completed!"); + log.display("**> visibmethod003a: \"quit\" signal recieved!"); + log.display("**> visibmethod003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } if ( ! instruction.equals("continue")) { @@ -90,24 +79,24 @@ public static void main (String argv[]) { System.exit(2/*STATUS_FAILED*/ + 95/*STATUS_TEMP*/); } - print_log_on_verbose("**> visibmethod003a: \"continue\" signal recieved!"); - print_log_on_verbose("**> visibmethod003a: enforce to unload checked class..."); + log.display("**> visibmethod003a: \"continue\" signal recieved!"); + log.display("**> visibmethod003a: enforce to unload checked class..."); boolean test_class_loader_finalized = classUnloader.unloadClass(); if ( ! test_class_loader_finalized ) { - print_log_on_verbose("**> visibmethod003a: checked class may be NOT unloaded!"); + log.display("**> visibmethod003a: checked class may be NOT unloaded!"); pipe.println("not_unloaded"); } else { - print_log_on_verbose("**> visibmethod003a: checked class unloaded!"); + log.display("**> visibmethod003a: checked class unloaded!"); pipe.println("ready2"); } - print_log_on_verbose("**> visibmethod003a: waiting for \"quit\" signal..."); + log.display("**> visibmethod003a: waiting for \"quit\" signal..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod003a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod003a: completed!"); + log.display("**> visibmethod003a: \"quit\" signal recieved!"); + log.display("**> visibmethod003a: completed!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibmethod003a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004/TestDescription.java index ebbcfcaeff48..0f4d7dbebb71 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004/TestDescription.java @@ -45,7 +45,6 @@ * nsk.jdi.ReferenceType.visibleMethods.visibmethod004a * @run driver * nsk.jdi.ReferenceType.visibleMethods.visibmethod004 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004a.java index 61c2160f7944..8a58e461060d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,44 +27,28 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibmethod004 JDI test. */ public class visibmethod004a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation - - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } + private static Log log = new Log(System.err); public static void main (String argv[]) { - for (int i=0; i visibmethod004a: debugee started!"); + log.display("**> visibmethod004a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); visibmethod004aClassForCheck class_for_check = new visibmethod004aClassForCheck(); - print_log_on_verbose("**> visibmethod004a: waiting for \"quit\" signal..."); + log.display("**> visibmethod004a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod004a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod004a: completed succesfully!"); + log.display("**> visibmethod004a: \"quit\" signal recieved!"); + log.display("**> visibmethod004a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("##> visibmethod004a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005/TestDescription.java index 5d8711f225dd..5a611156bc00 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005/TestDescription.java @@ -47,7 +47,6 @@ * nsk.jdi.ReferenceType.visibleMethods.visibmethod005a * @run driver * nsk.jdi.ReferenceType.visibleMethods.visibmethod005 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005a.java index a1c74711229f..77ab28aea36e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/visibleMethods/visibmethod005a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,37 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the visibmethod005 JDI test. */ public class visibmethod005a { - static boolean verbose_mode = false; // debugger may switch to true - // - for more easy failure evaluation + private static Log log = new Log(System.err); + private final static String package_prefix = "nsk.jdi.ReferenceType.visibleMethods."; // package_prefix = ""; // for DEBUG without package static String checked_class_name = package_prefix + "visibmethod005aInterfaceForCheck"; - - private static void print_log_on_verbose(String message) { - if ( verbose_mode ) { - System.err.println(message); - } - } - public static void main (String argv[]) { - for (int i=0; i visibmethod005a: debugee started!"); + log.display("**> visibmethod005a: debugee started!"); ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); @@ -65,23 +50,21 @@ public static void main (String argv[]) { try { checked_class_classobj = Class.forName(checked_class_name, true, visibmethod005a.class.getClassLoader()); - print_log_on_verbose - ("--> visibmethod005a: checked class loaded:" + checked_class_name); + log.display("--> visibmethod005a: checked class loaded:" + checked_class_name); } catch ( Throwable thrown ) { // ClassNotFoundException // System.err.println // ("**> visibmethod005a: load class: Throwable thrown = " + thrown.toString()); - print_log_on_verbose - ("--> visibmethod005a: checked class NOT loaded: " + checked_class_name); + log.display("--> visibmethod005a: checked class NOT loaded: " + checked_class_name); // Debuuger finds this fact itself } - print_log_on_verbose("**> visibmethod005a: waiting for \"quit\" signal..."); + log.display("**> visibmethod005a: waiting for \"quit\" signal..."); pipe.println("ready"); String instruction = pipe.readln(); if (instruction.equals("quit")) { - print_log_on_verbose("**> visibmethod005a: \"quit\" signal recieved!"); - print_log_on_verbose("**> visibmethod005a: completed succesfully!"); + log.display("**> visibmethod005a: \"quit\" signal recieved!"); + log.display("**> visibmethod005a: completed succesfully!"); System.exit(0/*STATUS_PASSED*/ + 95/*STATUS_TEMP*/); } System.err.println("!!**> visibmethod005a: unexpected signal (no \"quit\") - " + instruction); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001.java index da26eb37857b..af705bd47201 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001.java @@ -119,11 +119,7 @@ private int runThis (String argv[], PrintStream out) { logHandler = new Log(out, argsHandler); Binder binder = new Binder(argsHandler, logHandler); - if (argsHandler.verbose()) { - debugee = binder.bindToDebugee(debugeeName + " -vbs"); // *** tp - } else { - debugee = binder.bindToDebugee(debugeeName); // *** tp - } + debugee = binder.bindToDebugee(debugeeName); IOPipe pipe = new IOPipe(debugee); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001/TestDescription.java index 93b28f0daf1f..bb322adc1979 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001/TestDescription.java @@ -63,7 +63,6 @@ * nsk.jdi.VirtualMachine.classesByName.classesbyname001a * @run driver * nsk.jdi.VirtualMachine.classesByName.classesbyname001 - * -verbose * -arch=${os.family}-${os.simpleArch} * -waittime=5 * -debugee.vmkind=java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001a.java index 470263e5e9bc..476c3c53a2ac 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/classesByName/classesbyname001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,34 +27,22 @@ import nsk.share.jpda.*; import nsk.share.jdi.*; - /** * This class is used as debugee application for the classesbyname001 JDI test. */ public class classesbyname001a { + private static Log log = new Log(System.err); + //----------------------------------------------------- template section static final int PASSED = 0; static final int FAILED = 2; static final int PASS_BASE = 95; - //-------------------------------------------------- log procedures - static boolean verbose_mode = false; // debugger may switch to true - - private static void log1(String message) { - if (verbose_mode) - System.err.println("**> classesbyname001a: " + message); - } - - private static void logErr(String message) { - if (verbose_mode) - System.err.println("!!**> classesbyname001a: " + message); - } - //====================================================== test program //------------------------------------------------------ common section @@ -63,28 +51,21 @@ private static void logErr(String message) { public static void main (String argv[]) { - for (int i=0; i classesbyname001a: debugee started!"); // informing debuger of readyness ArgumentHandler argHandler = new ArgumentHandler(argv); IOPipe pipe = argHandler.createDebugeeIOPipe(); pipe.println("ready"); - int exitCode = PASSED; for (int i = 0; ; i++) { String instruction; - log1("waiting for an instruction from the debuger ..."); + log.display("**> classesbyname001a: waiting for an instruction from the debuger ..."); instruction = pipe.readln(); if (instruction.equals("quit")) { - log1("'quit' recieved"); + log.display("**> classesbyname001a: 'quit' recieved"); break ; } @@ -122,15 +103,12 @@ public static void main (String argv[]) { pipe.println("checkready"); break ; - // not a fully qualified name case 7: pipe.println("checkready"); break ; - - //------------------------------------------------- standard end section default: @@ -139,8 +117,8 @@ public static void main (String argv[]) { } } else { - logErr("unexpected instruction: " + instruction); - logErr("FAILED!"); + log.complain("classesbyname001a: unexpected instruction: " + instruction); + log.complain("classesbyname001a: FAILED!"); exitCode = 2; break ; } @@ -150,7 +128,6 @@ public static void main (String argv[]) { } } - class Class1ForCheck { // static fields From 4b31fdd5d2c16c49d63647d8cbd7ff42640e61cc Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 26 Aug 2026 16:17:33 +0000 Subject: [PATCH 091/223] 8391022: [valhalla] Missed ValueObjectMethods class initialization in JVM_IHashCode() Reviewed-by: fparain, liach --- src/hotspot/share/prims/jvm.cpp | 1 + .../TestValueObjectMethodsInit.java | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 4395df835f81..bf4fc4b961a0 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -808,6 +808,7 @@ JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) Handle ho(THREAD, obj); args.push_oop(ho); methodHandle method(THREAD, Universe::value_object_hash_code_method()); + method->method_holder()->initialize(CHECK_0); // Ensure class ValueObjectMethods is initialized JavaCalls::call(&result, method, &args, THREAD); Exceptions::wrap_exception_in_internal_error("Internal error in hashCode", CHECK_0); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java new file mode 100644 index 000000000000..dedbe4be227b --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Test ValueObjectMethods class initialization + * @bug 8391022 + * @requires vm.cds.supports.aot.class.linking + * @comment DeoptimizeALot flag requires debug VM + * @requires vm.debug + * @library /test/lib + * @enablePreview + * @modules java.base/jdk.internal.value + * @build TestValueObjectMethodsInit + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * ValueObjectMethodsClassApp + * ValueObjectMethodsClassApp$Value + * @run driver TestValueObjectMethodsInit + */ + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestValueObjectMethodsInit { + public static void main(String[] args) throws Exception { + final String appJar = ClassFileInstaller.getJarPath("app.jar"); + final String aotConfigFile = "app.aotconfig"; + final String aotCacheFile = "app.aot"; + final String appClass = "ValueObjectMethodsClassApp"; + + ProcessBuilder pb; + OutputAnalyzer out; + + // first make sure we have a valid aotConfigFile + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "--enable-preview", + "-XX:CompileThresholdScaling=0.01", + "-Xlog:aot", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, appClass); + + out = CDSTestUtils.executeAndLog(pb, "train"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "--enable-preview", + "-Xlog:aot", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "--enable-preview", + "-XX:CompileThresholdScaling=0.01", + "-XX:+DeoptimizeALot", + "-Xlog:aot", + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar, appClass); + + out = CDSTestUtils.executeAndLog(pb, "production"); + out.shouldHaveExitValue(0); + } +} + +class ValueObjectMethodsClassApp { + private static int hash; + + static value class Value { + private final int val; + Value(int i) { + val = i; + } + } + + static int test(int i) { + return System.identityHashCode(new Value(i)); + } + + public static void main(String[] args) { + // 1000 iterations are enough since we use CompileThresholdScaling=0.01 + for (int i = 0; i < 1000; i++) { + hash = test(i); + } + System.out.println("Hash: " + hash); + } +} From cd63012611cea61d7dc9ad3468fdb8a5a87ff99b Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 26 Aug 2026 17:02:35 +0000 Subject: [PATCH 092/223] 8388530: JDI and JDWP spec cleanup to get rid of "if preview is enabled" Reviewed-by: alanb, sspitsyn --- src/java.se/share/data/jdwp/jdwp.spec | 25 +++++++++++++++---- .../classes/com/sun/jdi/ObjectReference.java | 15 +++++++---- .../classes/com/sun/jdi/ReferenceType.java | 10 +++++--- .../share/classes/com/sun/jdi/StackFrame.java | 10 +++++--- .../share/classes/com/sun/jdi/Value.java | 12 ++++----- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index c8cdb99d4a69..40557becb1f6 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -731,6 +731,11 @@ JDWP "Java(tm) Debug Wire Protocol" "or one of its superclasses, superinterfaces, or implemented interfaces. " "Access control is not enforced; for example, the values of private " "fields can be obtained." + "

" + "When preview features are enabled in the target VM, " + "this command does not prevent a " + "strictly-initialized fieldPREVIEW " + "from being read before it has been initialized." (Out (referenceType refType "The reference type ID.") (Repeat fields "The number of values to get" @@ -1559,6 +1564,11 @@ JDWP "Java(tm) Debug Wire Protocol" "or one of its superclasses, superinterfaces, or implemented interfaces. " "Access control is not enforced; for example, the values of private " "fields can be obtained." + "

" + "When preview features are enabled in the target VM, " + "this command does not prevent a " + "strictly-initialized fieldPREVIEW " + "from being read before it has been initialized." (Out (object object "The object ID") (Repeat fields "The number of values to get" @@ -2129,8 +2139,9 @@ JDWP "Java(tm) Debug Wire Protocol" "language method. Forcing return on a thread with only one " "frame on the stack causes the thread to exit when resumed. " "

" - "When preview features are enabled, the method can not be the " - "constructor of a value class." + "When preview features are enabled in the target VM, " + "the method can not be the constructor of a " + "value classPREVIEW." "

" "For void methods, the value must be a void value. " "For methods that return primitive values, the value's type must " @@ -2605,8 +2616,10 @@ JDWP "Java(tm) Debug Wire Protocol" "index can be determined for method arguments from the method " "signature without access to the local variable table information.) " "

" - "When preview features are enabled, if the local variable is the 'this' " - "object and represents a value object under construction, the value returned " + "When preview features are enabled in the target VM, " + "if the local variable is the 'this' object and represents a " + "value objectPREVIEW " + "under construction, the value returned " "will be for a snapshot of the value object, not a reference to the actual " "value object under construction. Therefore the value returned will not reflect " "changes to the value object that happen later on during construction." @@ -2683,7 +2696,9 @@ JDWP "Java(tm) Debug Wire Protocol" "If the frame's method is static or native, the reply " "will contain the null object reference. " "

" - "When preview features are enabled and 'this' represents a value object + "When preview features are enabled on the target VM, " + "if 'this' represents a " + "value objectPREVIEW " "under construction, the value returned will be for a snapshot of the " "value object, not a reference to the actual value object under " "construction. Therefore the value returned will not reflect " diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java index 33ea1b7ae1f3..079e486bf0ce 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java @@ -52,10 +52,12 @@ * takes ObjectReference as parameter may throw * {@link ObjectCollectedException} if the mirrored object has been * garbage collected. + * *

*
*

Value Objects

- * If preview features are enabled, JDI supports value objects and classes. + * The Java Debug Interface (JDI) supports debugging of programs that use + * {@linkplain Class#isValue() value objects}. * However, the support does in some cases deviate from identity object * support in behavior or expectations as noted below: *

@@ -66,6 +68,7 @@ * be obtained to see the updated state. See {@link StackFrame#thisObject}. *

*
+ * * @author Robert Field * @author Gordon Hirsch * @author James McIlree @@ -102,8 +105,9 @@ public interface ObjectReference extends Value { * the mirrored object's class or a superclass of that class. *
*
- * If preview features are enabled, this method does not prevent a - * strictly-initialized field from being read before it has been initialized. + * This method does not prevent a + * {@linkplain java.lang.reflect.Field#isStrictInit() strictly-initialized field} + * from being read before it has been initialized. *
*
* @@ -121,8 +125,9 @@ public interface ObjectReference extends Value { * the mirrored object's class or a superclass of that class. *
*
- * If preview features are enabled, this method does not prevent a - * strictly-initialized field from being read before it has been initialized. + * This method does not prevent a + * {@linkplain java.lang.reflect.Field#isStrictInit() strictly-initialized field} + * from being read before it has been initialized. *
*
* diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java b/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java index 66664db999d6..a50cf91010e4 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ReferenceType.java @@ -521,8 +521,9 @@ default ModuleReference module() { * superinterface, or an implemented interface. *
*
- * If preview features are enabled, this method does not prevent a - * strictly-initialized field from being read before it has been initialized. + * This method does not prevent a + * {@linkplain java.lang.reflect.Field#isStrictInit() strictly-initialized field} + * from being read before it has been initialized. *
*
* @param field the field containing the requested value @@ -540,8 +541,9 @@ default ModuleReference module() { * superinterface, or an implemented interface. *
*
- * If preview features are enabled, this method does not prevent a - * strictly-initialized field from being read before it has been initialized. + * This method does not prevent a + * {@linkplain java.lang.reflect.Field#isStrictInit() strictly-initialized field} + * from being read before it has been initialized. *
*
* diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/StackFrame.java b/src/jdk.jdi/share/classes/com/sun/jdi/StackFrame.java index 570a167038c3..4e2192b6abee 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/StackFrame.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/StackFrame.java @@ -96,14 +96,18 @@ public interface StackFrame extends Mirror, Locatable { * Returns the value of 'this' for the current frame. * The {@link ObjectReference} for 'this' is only available for * non-native instance methods. - *

- * If 'this' is a {@linkplain - * ObjectReference##valueObjects value objectPREVIEW} + * + *

+ *
+ * If 'this' is a + * {@linkplain ObjectReference##valueObjects value objectPREVIEW} * under construction, the returned {@code ObjectReference} will refer to a * snapshot of the value object, not a reference * to the actual value object under construction. Consequently, the returned * {@code ObjectReference} will not reflect changes to the value object that * happen later during construction. + *
+ *
* * @return an {@link ObjectReference}, or null if the frame represents * a native or static method. diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/Value.java b/src/jdk.jdi/share/classes/com/sun/jdi/Value.java index 19a0c98d1691..96fb1aeb46a5 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/Value.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/Value.java @@ -31,14 +31,14 @@ * The mirror for a value in the target VM. * This interface is the root of a * value hierarchy encompassing primitive values and object values. + * *
*
- * When preview features are enabled, JDI supports value classes. A "value class" - * as supported in the Java language is not related to the JDI Value interface. - * A "value class" is a class declared with the "value" modifier. The JDI - * Value interface is used by JDI to mirror a value in the debuggee VM. For more - * information on value classes, see Section {@jls value-objects-8.1.1.5 Value Classes} - * of The Java Language Specification. + * The Java Debug Interface (JDI) supports debugging of programs that use + * {@linkplain Class#isValue() value objects}. A value object is an instance of a + * value class, declared with the value modifier. The JDI + * {@code com.sun.jdi.Value} interface is used to mirror a value in the target VM. + * That value may be a value object or an identity object. *
*
*

From 7a6258be5e96f97df75fb73da1dd95ec7dc255c8 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Wed, 26 Aug 2026 17:18:41 +0000 Subject: [PATCH 093/223] 8324871: Several container tests fail with java.io.tmpdir directory does not exist on linux-aarch64 cgroups-v2 Reviewed-by: lmesnik, sspitsyn --- test/hotspot/jtreg/containers/docker/ShareTmpDir.java | 2 +- test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java | 2 +- test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 4240ba408b76..065f9ed8a7be 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -75,7 +75,7 @@ private static void test() throws Exception { DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "WaitForFlagFile"); Object lock = new Object(); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); - opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp/"); + opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp/:z"); opts.addJavaOpts("-Xlog:os+container=trace", "-Xlog:perf*=debug", "-cp", "/test-classes/"); Thread t1 = new Thread() { diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index 68afe2b2db35..b6682ec37ebc 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -84,7 +84,7 @@ private static void testLimitUpdates() throws Exception { started.delete(); DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "LimitUpdateChecker"); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); - opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp"); + opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp:z"); opts.addDockerOpts("--cpu-period", Integer.toString(CPU_PERIOD)); opts.addDockerOpts("--cpu-quota", Integer.toString(INITIAL_CPU_COUNT * CPU_PERIOD)); opts.addDockerOpts("--memory", "500m"); diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index f1223f685c0e..0d3d84ecd4f0 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -83,7 +83,7 @@ private static void testLimitUpdates() throws Exception { started.delete(); DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "LimitUpdateChecker"); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); - opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp"); + opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp:z"); opts.addDockerOpts("--cpu-period", Integer.toString(CPU_PERIOD)); opts.addDockerOpts("--cpu-quota", Integer.toString(INITIAL_CPU_COUNT * CPU_PERIOD)); opts.addDockerOpts("--memory", "500m"); From 5b96789fcb72acbafaea6a47e63ba6a4f201da05 Mon Sep 17 00:00:00 2001 From: Alexandre Iline Date: Wed, 26 Aug 2026 17:21:05 +0000 Subject: [PATCH 094/223] 8390906: Allow to collect per-test code coverage information Reviewed-by: erikj --- doc/testing.html | 20 +++++++++++++++++++- doc/testing.md | 24 +++++++++++++++++++++++- make/RunTests.gmk | 16 +++++++++++++++- make/conf/jib-profiles.js | 4 ++-- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/doc/testing.html b/doc/testing.html index 648bc8baa6ae..f52f72ac2f7d 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -424,11 +424,29 @@

JCOV

For more fine-grained control, you can pass arbitrary filters to JCov using --with-jcov-filters, and you can specify a specific JDK to instrument using --with-jcov-input-jdk.

+

The resulting coverage is written into +build/$BUILD/test-results/jcov-output/result.xml.

The JCov report is stored in build/$BUILD/test-results/jcov-output/report.

Please note that running with JCov reporting can be very memory intensive.

-

JCOV_DIFF_CHANGESET

+
JCov scales
+

JCov scales make it possible to record which tests cover each part of +the instrumented code. To collect coverage with scales, set +JCOV_SCALES=true, for example:

+
$ make jcov-test TEST=jdk_lang TEST_OPTS="JCOV_SCALES=true"
+

The resulting coverage data contains the association between covered +code and the tests that covered it. A corresponding +testlist.txt file, which contains the test names, is +generated in the same directory.

+

The JCov report displays the names of the tests that cover each +class.

+

Collecting coverage scales forces jtreg tests to be run in +othervm mode, which takes longer than ordinary JCov +collection. The coverage data is also larger because it includes scale +information, and the generated report is larger because it includes test +names.

+
JCOV_DIFF_CHANGESET

While collecting code coverage with JCov, it is also possible to find coverage for only recently changed code. JCOV_DIFF_CHANGESET specifies a source revision. A textual report will be generated showing coverage of diff --git a/doc/testing.md b/doc/testing.md index 1de6c94b679f..e02a9e09d4e7 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -353,11 +353,33 @@ For more fine-grained control, you can pass arbitrary filters to JCov using `--with-jcov-filters`, and you can specify a specific JDK to instrument using `--with-jcov-input-jdk`. +The resulting coverage is written into +`build/$BUILD/test-results/jcov-output/result.xml`. + The JCov report is stored in `build/$BUILD/test-results/jcov-output/report`. Please note that running with JCov reporting can be very memory intensive. -#### JCOV_DIFF_CHANGESET +##### JCov scales + +JCov scales make it possible to record which tests cover each part of the +instrumented code. To collect coverage with scales, set `JCOV_SCALES=true`, +for example: + + $ make jcov-test TEST=jdk_lang TEST_OPTS="JCOV_SCALES=true" + +The resulting coverage data contains the association between covered code and +the tests that covered it. A corresponding `testlist.txt` file, which contains +the test names, is generated in the same directory. + +The JCov report displays the names of the tests that cover each class. + +Collecting coverage scales forces jtreg tests to be run in `othervm` mode, +which takes longer than ordinary JCov collection. The coverage data is also +larger because it includes scale information, and the generated report is +larger because it includes test names. + +##### JCOV_DIFF_CHANGESET While collecting code coverage with JCov, it is also possible to find coverage for only recently changed code. JCOV_DIFF_CHANGESET specifies a source diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 1433ab32e5ce..1013f38baa77 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -45,7 +45,7 @@ ifneq ($(TEST_VM_OPTS), ) endif $(eval $(call ParseKeywordVariable, TEST_OPTS, \ - SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR JCOV JCOV_DIFF_CHANGESET AOT_JDK, \ + SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR JCOV JCOV_DIFF_CHANGESET JCOV_SCALES AOT_JDK, \ STRING_KEYWORDS := VM_OPTIONS JAVA_OPTIONS, \ )) @@ -121,9 +121,21 @@ ifeq ($(TEST_OPTS_JCOV), true) JCOV_SUPPORT_DIR := $(TEST_SUPPORT_DIR)/jcov-support JCOV_GRABBER_LOG := $(JCOV_OUTPUT_DIR)/grabber.log JCOV_RESULT_FILE := $(JCOV_OUTPUT_DIR)/result.xml + JCOV_TESTLIST := $(JCOV_OUTPUT_DIR)/testlist.txt JCOV_REPORT := $(JCOV_OUTPUT_DIR)/report + JCOV_GRABBER_OPTIONS ?= + JCOV_REPGEN_OPTIONS ?= + TEST_OPTS_JCOV_SCALES ?= false JCOV_MEM_OPTIONS := -Xms64m -Xmx4g + ifeq ($(TEST_OPTS_JCOV_SCALES), true) + JCOV_GRABBER_OPTIONS += -scale -mergebyname -outTestList $(JCOV_TESTLIST) + TEST_JOBS := 1 + JTREG_TEST_MODE := othervm + JTREG_VM_OPTIONS += -Djcov.extension=com.sun.tdk.jcov.runtime.TestNameDecorator + JCOV_REPGEN_OPTIONS += -tests $(JCOV_TESTLIST) + endif + # Replace our normal test JDK with the JCov image. JDK_UNDER_TEST := $(JCOV_IMAGE_DIR) @@ -1414,6 +1426,7 @@ ifeq ($(TEST_OPTS_JCOV), true) fi $(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar Grabber -v -t \ $(JCOV_IMAGE_DIR)/template.xml -o $(JCOV_RESULT_FILE) \ + $(JCOV_GRABBER_OPTIONS) \ 1>$(JCOV_GRABBER_LOG) 2>&1 & jcov-start-grabber: jcov-do-start-grabber @@ -1441,6 +1454,7 @@ ifeq ($(TEST_OPTS_JCOV), true) `$(ECHO) $(TOPDIR)/src/*/share/classes/ | $(TR) ' ' ':'` -fmt html \ $(JCOV_MODULES_FILTER) $(JCOV_FILTERS) \ -mainReportTitle "$(JCOV_REPORT_TITLE)" \ + $(JCOV_REPGEN_OPTIONS) \ -o $(JCOV_REPORT) $(JCOV_RESULT_FILE)) TARGETS += jcov-do-start-grabber jcov-start-grabber jcov-stop-grabber \ diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 32f07325c058..c7f9fa87a51e 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1192,8 +1192,8 @@ var getJibProfilesDependencies = function (input, common) { server: "jpg", product: "jcov", version: "3.0", - build_number: "6", - file: "bundles/jcov-3.0+6.zip", + build_number: "9", + file: "bundles/jcov-3.0+9.zip", environment_name: "JCOV_HOME", }, From 30df8a5af29ff682f9b6d50e51c46efcf19c920f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 26 Aug 2026 17:25:42 +0000 Subject: [PATCH 095/223] 8383460: Replace "sharing" in VM version string with "aot" information Reviewed-by: kvn, asmehra --- .../share/runtime/abstract_vm_version.cpp | 44 +++++++++---------- src/hotspot/share/runtime/arguments.cpp | 8 +++- src/hotspot/share/runtime/threads.cpp | 10 ++++- src/hotspot/share/utilities/vmError.cpp | 4 +- .../runtime/cds/appcds/aotFlags/AOTFlags.java | 6 +-- 5 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 37c5815f60e3..702909409a76 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "runtime/os.hpp" #include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" const char* Abstract_VM_Version::_s_vm_release = Abstract_VM_Version::vm_release(); const char* Abstract_VM_Version::_s_internal_vm_info_string = Abstract_VM_Version::internal_vm_info_string(); @@ -140,31 +141,28 @@ const char* Abstract_VM_Version::vm_vendor() { // The VM info string should be a constant, but its value cannot be finalized until after VM arguments -// have been fully processed. And we want to avoid dynamic memory allocation which will cause ASAN -// report error, so we enumerate all the cases by static const string value. +// have been fully processed. The result is C-heap allocated, and should be freed by the caller. const char* Abstract_VM_Version::vm_info_string() { + stringStream ss; switch (Arguments::mode()) { - case Arguments::_int: - if (is_vm_statically_linked()) { - return CDSConfig::is_using_archive() ? "interpreted mode, static, sharing" : "interpreted mode, static"; - } else { - return CDSConfig::is_using_archive() ? "interpreted mode, sharing" : "interpreted mode"; - } - case Arguments::_mixed: - if (is_vm_statically_linked()) { - return CDSConfig::is_using_archive() ? "mixed mode, static, sharing" : "mixed mode, static"; - } else { - return CDSConfig::is_using_archive() ? "mixed mode, sharing" : "mixed mode"; - } - case Arguments::_comp: - if (is_vm_statically_linked()) { - return CDSConfig::is_using_archive() ? "compiled mode, static, sharing" : "compiled mode, static"; - } else { - return CDSConfig::is_using_archive() ? "compiled mode, sharing" : "compiled mode"; - } + case Arguments::_int: ss.print("%s", "interpreted mode"); break; + case Arguments::_mixed: ss.print("%s", "mixed mode"); break; + case Arguments::_comp: ss.print("%s", "compiled mode"); break; + default: ShouldNotReachHere(); } - ShouldNotReachHere(); - return ""; + + if (is_vm_statically_linked()) { + ss.print("%s", ", static"); + } + if (CDSConfig::is_dumping_preimage_static_archive()) { + ss.print("%s", ", aot training"); + } else if (CDSConfig::is_dumping_final_static_archive()) { + ss.print("%s", ", aot assembly"); + } else if (CDSConfig::is_using_archive()) { + ss.print("%s", CDSConfig::new_aot_flags_used() ? ", aot production" : ", sharing"); + } + + return ss.as_string(/*c_heap=*/true); } // NOTE: do *not* use stringStream. this function is called by diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 003e2d0fbfa4..136316fcffdf 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -400,7 +400,9 @@ void Arguments::init_system_properties() { PropertyList_add(&_system_properties, new SystemProperty("jdk.debug", VM_Version::jdk_debug_level(), false)); // Initialize the vm.info now, but it will need updating after argument parsing. - _vm_info = new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true); + const char* vm_info_str = VM_Version::vm_info_string(); + _vm_info = new SystemProperty("java.vm.info", vm_info_str, true); + FREE_C_HEAP_ARRAY(vm_info_str); // Following are JVMTI agent writable properties. // Properties values are set to nullptr and they are @@ -1347,8 +1349,10 @@ void Arguments::set_mode_flags(Mode mode) { // Ensure Agent_OnLoad has the correct initial values. // This may not be the final mode; mode may change later in onload phase. + const char* vm_info_str = VM_Version::vm_info_string(); PropertyList_unique_add(&_system_properties, "java.vm.info", - VM_Version::vm_info_string(), AddProperty, UnwriteableProperty, ExternalProperty); + vm_info_str, AddProperty, UnwriteableProperty, ExternalProperty); + FREE_C_HEAP_ARRAY(vm_info_str); UseInterpreter = true; UseCompiler = true; diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 6663966f36e0..1000a7563dfd 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -667,7 +667,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // is initially computed. See Abstract_VM_Version::vm_info_string(). // This update must happen before we initialize the java classes, but // after any initialization logic that might modify the flags. - Arguments::update_vm_info_property(VM_Version::vm_info_string()); + const char* vm_info_str = VM_Version::vm_info_string(); + Arguments::update_vm_info_property(vm_info_str); + FREE_C_HEAP_ARRAY(vm_info_str); JavaThread* THREAD = JavaThread::current(); // For exception macros. HandleMark hm(THREAD); @@ -1327,10 +1329,14 @@ void Threads::print_on(outputStream* st, bool print_stacks, char buf[32]; st->print_raw_cr(os::local_time_string(buf, sizeof(buf))); + const char* vm_info_str = VM_Version::vm_info_string(); st->print_cr("Full thread dump %s (%s %s)", VM_Version::vm_name(), VM_Version::vm_release(), - VM_Version::vm_info_string()); + vm_info_str); + FREE_C_HEAP_ARRAY(vm_info_str); + + JDK_Version::current().to_string(buf, sizeof(buf)); const char* runtime_name = JDK_Version::runtime_name() != nullptr ? JDK_Version::runtime_name() : ""; diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 10c15b3c09e2..6fb2cb96a029 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -516,18 +516,20 @@ static void report_vm_version(outputStream* st, char* buf, int buflen) { buf, jdk_debug_level, runtime_version); // This is the long version with some default settings added + const char* vm_info_str = VM_Version::vm_info_string(); st->print_cr("# Java VM: %s%s%s (%s%s, %s%s%s%s, %s, %s)", VM_Version::vm_name(), (*vendor_version != '\0') ? " " : "", vendor_version, jdk_debug_level, VM_Version::vm_release(), - VM_Version::vm_info_string(), + vm_info_str, TieredCompilation ? ", tiered" : "", UseCompressedOops ? ", compressed oops" : "", UseCompactObjectHeaders ? ", compact obj headers" : "", GCConfig::hs_err_name(), VM_Version::vm_platform_string() ); + FREE_C_HEAP_ARRAY(vm_info_str); } // Returns true if at least one thread reported a fatal error and fatal error handling is in process. diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java index 718793902390..fc24f341ff36 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java @@ -101,7 +101,7 @@ static void positiveTests() throws Exception { "-XX:AOTMode=off", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); - out.shouldNotContain(", sharing"); + out.shouldNotContain(", aot production"); out.shouldNotContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); @@ -115,7 +115,7 @@ static void positiveTests() throws Exception { "-XX:AOTMode=auto", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); - out.shouldContain(", sharing"); + out.shouldContain(", aot production"); out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); @@ -130,7 +130,7 @@ static void positiveTests() throws Exception { "-XX:AOTMode=" + mode, "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); - out.shouldContain(", sharing"); + out.shouldContain(", aot production"); out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); From edb2326b7d504d96c6ad06c3bf60ede7c0156889 Mon Sep 17 00:00:00 2001 From: Ashay Rane Date: Wed, 26 Aug 2026 17:57:53 +0000 Subject: [PATCH 096/223] 8383246: Add relaxed implementations of atomics for Windows/AArch64 Reviewed-by: dholmes, macarte --- .../atomicAccess_windows_aarch64.hpp | 128 +++++++++++-- .../gtest/runtime/test_atomicAccess.cpp | 179 ++++++++++++++++++ 2 files changed, 289 insertions(+), 18 deletions(-) diff --git a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp index 9238043f7a41..a92e000950fc 100644 --- a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp @@ -29,12 +29,6 @@ #include #include -// As per atomicAccess.hpp all read-modify-write operations have to provide two-way -// barriers semantics. The memory_order parameter is ignored - we always provide -// the strongest/most-conservative ordering -// -// For AARCH64 we add explicit barriers in the stubs. - template struct AtomicAccess::PlatformAdd { template @@ -56,9 +50,26 @@ struct AtomicAccess::PlatformAdd { I add_value, \ atomic_memory_order order) const { \ STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(D)); \ - return PrimitiveConversions::cast( \ - IntrinsicName(reinterpret_cast(dest), \ - PrimitiveConversions::cast(add_value))); \ + IntrinsicType volatile* d = \ + reinterpret_cast(dest); \ + IntrinsicType inc = \ + PrimitiveConversions::cast(add_value); \ + IntrinsicType result; \ + switch (order) { \ + case memory_order_relaxed: \ + result = _##IntrinsicName##_nf(d, inc); break; \ + case memory_order_acquire: \ + result = _##IntrinsicName##_acq(d, inc); break; \ + case memory_order_release: \ + result = _##IntrinsicName##_rel(d, inc); break; \ + case memory_order_conservative: \ + result = _##IntrinsicName(d, inc); \ + OrderAccess::fence(); \ + break; \ + default: \ + result = _##IntrinsicName(d, inc); break; \ + } \ + return PrimitiveConversions::cast(result); \ } DEFINE_INTRINSIC_ADD(InterlockedAdd, long) @@ -78,9 +89,26 @@ struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {}; STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \ STATIC_ASSERT(sizeof(IntrinsicType) == 4 || \ sizeof(IntrinsicType) == 8); \ - return PrimitiveConversions::cast( \ - IntrinsicName(reinterpret_cast(dest), \ - PrimitiveConversions::cast(exchange_value))); \ + IntrinsicType volatile* d = \ + reinterpret_cast(dest); \ + IntrinsicType xchg = \ + PrimitiveConversions::cast(exchange_value); \ + IntrinsicType result; \ + switch (order) { \ + case memory_order_relaxed: \ + result = _##IntrinsicName##_nf(d, xchg); break; \ + case memory_order_acquire: \ + result = _##IntrinsicName##_acq(d, xchg); break; \ + case memory_order_release: \ + result = _##IntrinsicName##_rel(d, xchg); break; \ + case memory_order_conservative: \ + result = _##IntrinsicName(d, xchg); \ + OrderAccess::fence(); \ + break; \ + default: \ + result = _##IntrinsicName(d, xchg); break; \ + } \ + return PrimitiveConversions::cast(result); \ } DEFINE_INTRINSIC_XCHG(InterlockedExchange, long) @@ -90,7 +118,9 @@ DEFINE_INTRINSIC_XCHG(InterlockedExchange64, __int64) // Note: the order of the parameters is different between // AtomicAccess::PlatformCmpxchg<*>::operator() and the -// InterlockedCompareExchange* API. +// _InterlockedCompareExchange* intrinsics: +// HotSpot: (dest, compare_value, exchange_value) +// MSVC: (dest, exchange_value, compare_value) #define DEFINE_INTRINSIC_CMPXCHG(IntrinsicName, IntrinsicType) \ template<> \ @@ -100,16 +130,78 @@ DEFINE_INTRINSIC_XCHG(InterlockedExchange64, __int64) T exchange_value, \ atomic_memory_order order) const { \ STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T)); \ - return PrimitiveConversions::cast( \ - IntrinsicName(reinterpret_cast(dest), \ - PrimitiveConversions::cast(exchange_value), \ - PrimitiveConversions::cast(compare_value))); \ + IntrinsicType volatile* d = \ + reinterpret_cast(dest); \ + IntrinsicType xchg = \ + PrimitiveConversions::cast(exchange_value); \ + IntrinsicType cmp = \ + PrimitiveConversions::cast(compare_value); \ + IntrinsicType result; \ + switch (order) { \ + case memory_order_relaxed: \ + result = _##IntrinsicName##_nf(d, xchg, cmp); break; \ + case memory_order_acquire: \ + result = _##IntrinsicName##_acq(d, xchg, cmp); break; \ + case memory_order_release: \ + result = _##IntrinsicName##_rel(d, xchg, cmp); break; \ + case memory_order_conservative: \ + result = _##IntrinsicName(d, xchg, cmp); \ + OrderAccess::fence(); \ + break; \ + default: \ + result = _##IntrinsicName(d, xchg, cmp); break; \ + } \ + return PrimitiveConversions::cast(result); \ } -DEFINE_INTRINSIC_CMPXCHG(_InterlockedCompareExchange8, char) // Use the intrinsic as InterlockedCompareExchange8 does not exist +DEFINE_INTRINSIC_CMPXCHG(InterlockedCompareExchange8, char) // Use the intrinsic as InterlockedCompareExchange8 does not exist DEFINE_INTRINSIC_CMPXCHG(InterlockedCompareExchange, long) DEFINE_INTRINSIC_CMPXCHG(InterlockedCompareExchange64, __int64) #undef DEFINE_INTRINSIC_CMPXCHG +#define DEFINE_ORDERED_LOAD(Size, Name, Type) \ + template<> \ + struct AtomicAccess::PlatformOrderedLoad { \ + template \ + T operator()(const volatile T* p) const { \ + T* noconst_ptr = const_cast(p); \ + unsigned Type value = Name(reinterpret_cast(noconst_ptr)); \ + return PrimitiveConversions::cast(value); \ + } \ + }; + +DEFINE_ORDERED_LOAD(1, __ldar8, __int8) +DEFINE_ORDERED_LOAD(2, __ldar16, __int16) +DEFINE_ORDERED_LOAD(4, __ldar32, __int32) +DEFINE_ORDERED_LOAD(8, __ldar64, __int64) + +#undef DEFINE_ORDERED_LOAD + +#define DEFINE_ORDERED_STORE(Size, Name, Type) \ + template<> \ + struct AtomicAccess::PlatformOrderedStore { \ + template \ + void operator()(volatile T* p, T v) const { \ + Name(reinterpret_cast(p), PrimitiveConversions::cast(v)); \ + } \ + }; + +DEFINE_ORDERED_STORE(1, __stlr8, __int8) +DEFINE_ORDERED_STORE(2, __stlr16, __int16) +DEFINE_ORDERED_STORE(4, __stlr32, __int32) +DEFINE_ORDERED_STORE(8, __stlr64, __int64) + +#undef DEFINE_ORDERED_STORE + +template +struct AtomicAccess::PlatformOrderedStore +{ + template + void operator()(volatile T* p, T v) const { + PlatformOrderedStore()(p, v); + OrderAccess::fence(); + } +}; + #endif // OS_CPU_WINDOWS_AARCH64_ATOMICACCESS_WINDOWS_AARCH64_HPP diff --git a/test/hotspot/gtest/runtime/test_atomicAccess.cpp b/test/hotspot/gtest/runtime/test_atomicAccess.cpp index a489be71b192..908bd603e834 100644 --- a/test/hotspot/gtest/runtime/test_atomicAccess.cpp +++ b/test/hotspot/gtest/runtime/test_atomicAccess.cpp @@ -351,3 +351,182 @@ TEST_VM(AtomicAccessBitopsTest, int64) { TEST_VM(AtomicAccessBitopsTest, uint64) { AtomicAccessBitopsTestSupport()(); } + +// The following tests verify that atomic operations produce correct results for +// each atomic_memory_order value. They don't verify the actual ordering +// semantics (which would require multi-threaded stress tests). + +static const atomic_memory_order memory_orders[] = { + memory_order_relaxed, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst, + memory_order_conservative, +}; + +template +struct AtomicAccessOrderedAddTestSupport { + volatile T _test_value; + + AtomicAccessOrderedAddTestSupport() : _test_value{} {} + + void test_add(atomic_memory_order order) { + T zero = 0; + T five = 5; + AtomicAccess::store(&_test_value, zero); + T value = AtomicAccess::add(&_test_value, five, order); + EXPECT_EQ(five, value); + EXPECT_EQ(five, AtomicAccess::load(&_test_value)); + } + + void test_fetch_add(atomic_memory_order order) { + T zero = 0; + T five = 5; + AtomicAccess::store(&_test_value, zero); + T value = AtomicAccess::fetch_then_add(&_test_value, five, order); + EXPECT_EQ(zero, value); + EXPECT_EQ(five, AtomicAccess::load(&_test_value)); + } +}; + +TEST_VM(AtomicAccessOrderedAddTest, int32) { + using Support = AtomicAccessOrderedAddTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test_add(order); + Support().test_fetch_add(order); + } +} + +TEST_VM(AtomicAccessOrderedAddTest, int64) { + using Support = AtomicAccessOrderedAddTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test_add(order); + Support().test_fetch_add(order); + } +} + +template +struct AtomicAccessOrderedXchgTestSupport { + volatile T _test_value; + + AtomicAccessOrderedXchgTestSupport() : _test_value{} {} + + void test(atomic_memory_order order) { + T zero = 0; + T five = 5; + AtomicAccess::store(&_test_value, zero); + T res = AtomicAccess::xchg(&_test_value, five, order); + EXPECT_EQ(zero, res); + EXPECT_EQ(five, AtomicAccess::load(&_test_value)); + } +}; + +TEST_VM(AtomicAccessOrderedXchgTest, int32) { + using Support = AtomicAccessOrderedXchgTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test(order); + } +} + +TEST_VM(AtomicAccessOrderedXchgTest, int64) { + using Support = AtomicAccessOrderedXchgTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test(order); + } +} + +template +struct AtomicAccessOrderedCmpxchgTestSupport { + volatile T _test_value; + + AtomicAccessOrderedCmpxchgTestSupport() : _test_value{} {} + + void test(atomic_memory_order order) { + T zero = 0; + T five = 5; + T ten = 10; + + // Failed cmpxchg: compare_value does not match. + AtomicAccess::store(&_test_value, zero); + T res = AtomicAccess::cmpxchg(&_test_value, five, ten, order); + EXPECT_EQ(zero, res); + EXPECT_EQ(zero, AtomicAccess::load(&_test_value)); + + // Successful cmpxchg: compare_value matches. + res = AtomicAccess::cmpxchg(&_test_value, zero, ten, order); + EXPECT_EQ(zero, res); + EXPECT_EQ(ten, AtomicAccess::load(&_test_value)); + } +}; + +TEST_VM(AtomicAccessOrderedCmpxchgTest, int8) { + using Support = AtomicAccessOrderedCmpxchgTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test(order); + } +} + +TEST_VM(AtomicAccessOrderedCmpxchgTest, int32) { + using Support = AtomicAccessOrderedCmpxchgTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test(order); + } +} + +TEST_VM(AtomicAccessOrderedCmpxchgTest, int64) { + using Support = AtomicAccessOrderedCmpxchgTestSupport; + for (atomic_memory_order order : memory_orders) { + Support().test(order); + } +} + +template +struct AtomicAccessOrderedLoadStoreTestSupport { + volatile T _test_value; + + AtomicAccessOrderedLoadStoreTestSupport() : _test_value{} {} + + void test_release_store_load_acquire(T value) { + AtomicAccess::release_store(&_test_value, value); + T loaded = AtomicAccess::load_acquire(&_test_value); + EXPECT_EQ(value, loaded); + } + + void test_release_store_fence(T value) { + AtomicAccess::release_store_fence(&_test_value, value); + T loaded = AtomicAccess::load_acquire(&_test_value); + EXPECT_EQ(value, loaded); + } +}; + +TEST_VM(AtomicAccessOrderedLoadStoreTest, int8) { + using Support = AtomicAccessOrderedLoadStoreTestSupport; + Support().test_release_store_load_acquire(42); + Support().test_release_store_fence(42); +} + +TEST_VM(AtomicAccessOrderedLoadStoreTest, int16) { + using Support = AtomicAccessOrderedLoadStoreTestSupport; + Support().test_release_store_load_acquire(1234); + Support().test_release_store_fence(1234); +} + +TEST_VM(AtomicAccessOrderedLoadStoreTest, int32) { + using Support = AtomicAccessOrderedLoadStoreTestSupport; + Support().test_release_store_load_acquire(123456); + Support().test_release_store_fence(123456); +} + +TEST_VM(AtomicAccessOrderedLoadStoreTest, int64) { + using Support = AtomicAccessOrderedLoadStoreTestSupport; + Support().test_release_store_load_acquire(1234567890LL); + Support().test_release_store_fence(1234567890LL); +} + +TEST_VM(AtomicAccessOrderedLoadStoreTest, ptr) { + int dummy[10] = {}; + using Support = AtomicAccessOrderedLoadStoreTestSupport; + Support().test_release_store_load_acquire(&dummy[5]); + Support().test_release_store_fence(&dummy[7]); +} From ab00564a0efecd5573ec9d3f10bc0c4a2d3106e5 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 26 Aug 2026 19:26:34 +0000 Subject: [PATCH 097/223] 8388833: Fix JDWP spec w.r.t. setting static final fields and provide warnings about setting final fields Reviewed-by: sspitsyn, alanb --- src/java.se/share/data/jdwp/jdwp.spec | 6 +- .../ClassType/SetValues/setvalues001.java | 73 +++++++++-- .../ClassType/SetValues/setvalues001a.java | 21 ++- .../SetValues/setvalues001.java | 122 ++++++++++++++++-- .../SetValues/setvalues001a.java | 31 ++++- 5 files changed, 223 insertions(+), 30 deletions(-) diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index 40557becb1f6..f8973fb1406d 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -1095,7 +1095,8 @@ JDWP "Java(tm) Debug Wire Protocol" "Each field must be member of the class type " "or one of its superclasses, superinterfaces, or implemented interfaces. " "Access control is not enforced; for example, the values of private " - "fields can be set. Final fields cannot be set." + "fields can be set. Setting a final static field is permitted but may " + "result in an unexpected exception or a fatal crash. " "For primitive values, the value's type must match the " "field's type exactly. For object values, there must exist a " "widening reference conversion from the value's type to the @@ -1596,7 +1597,8 @@ JDWP "Java(tm) Debug Wire Protocol" "Each field must be member of the object's type " "or one of its superclasses, superinterfaces, or implemented interfaces. " "Access control is not enforced; for example, the values of private " - "fields can be set. " + "fields can be set. Setting a final instance field is permitted but may " + "result in an unexpected exception or a fatal crash. " "For primitive values, the value's type must match the " "field's type exactly. For object values, there must be a " "widening reference conversion from the value's type to the diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001.java index e40906c299ae..36eb44df87a1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,10 @@ public class setvalues001 { static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass"; static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";"; + // tested final class name and signature constants + static final String TESTED_FINAL_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedFinalClass"; + static final String TESTED_FINAL_CLASS_SIGNATURE = "L" + TESTED_FINAL_CLASS_NAME.replace('.', '/') + ";"; + // target values class name and signature constants static final String TARGET_VALUES_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TargetValuesClass"; static final String TARGET_VALUES_CLASS_SIGNATURE = "L" + TARGET_VALUES_CLASS_NAME.replace('.', '/') + ";"; @@ -147,7 +151,7 @@ public int runIt(String argv[], PrintStream out) { log.display("Getting values of the static fields"); JDWP.Value targetValues[] = queryClassFieldValues(targetValuesClassID, targetValuesFieldIDs); - log.display(" got values: " + targetValues.length); + log.display(" got target values: " + targetValues.length); if (targetValues.length != count) { throw new Failure("Unexpected number of static fields values received: " + targetValues.length + "(expected: " + count + ")"); @@ -157,7 +161,7 @@ public int runIt(String argv[], PrintStream out) { log.display("Getting tested classID by signature:\n" + " " + TESTED_CLASS_SIGNATURE); long testedClassID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE); - log.display(" got classID: " + testedClassID); + log.display(" got tested classID: " + testedClassID); // query debugee for fieldIDs of tested class static fields log.display("Getting fieldIDs for static fields of the tested class"); @@ -168,14 +172,32 @@ public int runIt(String argv[], PrintStream out) { + testedFieldIDs.length + "(expected: " + count + ")"); } - // perform testing JDWP command - log.display("\n>>> Testing JDWP command \n"); + // query debugee for classID of the tested final class + log.display("Getting tested final classID by signature:\n" + + " " + TESTED_FINAL_CLASS_SIGNATURE); + long testedFinalClassID = debugee.getReferenceTypeID(TESTED_FINAL_CLASS_SIGNATURE); + log.display(" got tested final classID: " + testedFinalClassID); + + // query debugee for fieldIDs of tested final class static fields + log.display("Getting fieldIDs for static fields of the tested final class"); + long testedFinalFieldIDs[] = queryClassFieldIDs(testedFinalClassID); + log.display(" got fields: " + testedFinalFieldIDs.length); + if (testedFinalFieldIDs.length != count) { + throw new Failure("Unexpected number of static fields of tested final class received: " + + testedFinalFieldIDs.length + "(expected: " + count + ")"); + } + + log.display("\n>>> Testing JDWP ClassType.SetValues command on tested class\n"); testCommand(testedClassID, testedFieldIDs, targetValues); - // check confirmation from debuggee that values have been set properly - log.display("\n>>> Checking that the values have been set properly \n"); + log.display("\n>>> Checking with the debuggee that the values have been set properly\n"); checkValuesChanged(); + log.display("\n>>> Testing JDWP ClassType.SetValues command on tested final class\n"); + testCommand(testedFinalClassID, testedFinalFieldIDs, targetValues); + + log.display("\n>>> Checking with JDWP ClassType.GetValues that the values have been set properly \n"); + checkJDWPValuesChanged(testedFinalClassID, testedFinalFieldIDs, targetValues); } finally { // quit debugee log.display("\n>>> Finishing test \n"); @@ -399,7 +421,7 @@ void testCommand(long classID, long fieldIDs[], JDWP.Value values[]) { } /** - * Check confiramtion from debuggee that values are changed. + * Check confirmation from debuggee that values are changed. */ void checkValuesChanged() { // send debugee signal RUN @@ -426,4 +448,39 @@ void checkValuesChanged() { } } + /** + * Check confirmation using JDWP ClassType.GetValues that the values are changed. + */ + void checkJDWPValuesChanged(long testedClassID, long testedFieldIDs[], + JDWP.Value targetValues[]) { + // verify that JDWP ClassType.GetValues returns the expected values + int count = targetValues.length; + log.display("\n>>> Getting field values using JDWP ClassType.GetValues \n"); + JDWP.Value[] actualValues = queryClassFieldValues(testedClassID, testedFieldIDs); + log.display(" got actual values: " + actualValues.length); + if (actualValues.length != count) { + throw new Failure("Unexpected number of static field values received: " + + actualValues.length + "(expected: " + count + ")"); + } + for (int i = 0; i < count; i++) { + log.display(" field #" + i +":"); + log.display(" fieldID: " + testedFieldIDs[i]); + + JDWP.Value actualValue = actualValues[i]; + JDWP.Value targetValue = targetValues[i]; + JDWP.UntaggedValue untaggedActualValue = + new JDWP.UntaggedValue(actualValue.getValue()); + JDWP.UntaggedValue untaggedTargetValue = + new JDWP.UntaggedValue(targetValue.getValue()); + log.display(" untaggedActualValue: " + untaggedActualValue.getValue()); + log.display(" untaggedTargetValue: " + untaggedTargetValue.getValue()); + if (!untaggedActualValue.getValue().equals(untaggedTargetValue.getValue())) { + log.complain("JDWP found a static field that was not correctly set"); + success = false; + } + } + if (success) { + log.display("Verfied using JDWP ClassType.GetValues that all static fields values have been correctly set"); + } + } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001a.java index ff3eb2789d4b..26c9fa647d0b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ClassType/SetValues/setvalues001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public int runIt(String args[], PrintStream out) { OriginalValuesClass original = new OriginalValuesClass(); TargetValuesClass target = new TargetValuesClass(); TestedClass tested = new TestedClass(); + TestedFinalClass testedFinal = new TestedFinalClass(); // send debugger signal READY log.display("Sending signal to debugger: " + setvalues001.READY); @@ -279,7 +280,7 @@ static boolean checkValues() { } */ - // check taht no any changed value differs from target + // check that none of the changed values differs from target if (different > 0) { log.complain("Values of " + different + " fields have not been set correctly"); return false; @@ -303,7 +304,7 @@ public static class OriginalValuesClass { static final Object objectValue = new OriginalValuesClass(); } - // class with the original values of static fields + // class with the target values of static fields public static class TargetValuesClass { static final boolean booleanValue = false; static final byte byteValue = (byte)0x0F; @@ -331,4 +332,18 @@ public static class TestedClass { static Object objectValue = OriginalValuesClass.objectValue; } + // tested class with own static final fields values + public static class TestedFinalClass { + private static final boolean booleanValue = OriginalValuesClass.booleanValue; + private static final byte byteValue = OriginalValuesClass.byteValue; + protected static final char charValue = OriginalValuesClass.charValue; + protected static final int intValue = OriginalValuesClass.intValue; + public static final short shortValue = OriginalValuesClass.shortValue; + public static final long longValue = OriginalValuesClass.longValue; + static final float floatValue = OriginalValuesClass.floatValue; + static final double doubleValue = OriginalValuesClass.doubleValue; + static final String stringValue = OriginalValuesClass.stringValue; + static final Object objectValue = OriginalValuesClass.objectValue; + } + } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001.java index d9a7622ea042..6cfdaab2923a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,16 +67,21 @@ public class setvalues001 { static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass"; static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";"; + // tested final class name and signature constants + static final String TESTED_FINAL_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedFinalClass"; + static final String TESTED_FINAL_CLASS_SIGNATURE = "L" + TESTED_FINAL_CLASS_NAME.replace('.', '/') + ";"; + // target values class name and signature constants static final String TARGET_VALUES_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TargetValuesClass"; static final String TARGET_VALUES_CLASS_SIGNATURE = "L" + TARGET_VALUES_CLASS_NAME.replace('.', '/') + ";"; - // name and siagnature of a class with static field with the tested object value + // name and signature of a class with static field with the tested object value static final String OBJECT_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "ObjectClass"; static final String OBJECT_CLASS_SIGNATURE = "L" + OBJECT_CLASS_NAME.replace('.', '/') + ";"; - // name of the static field in the tested class with the tested object value + // name of the static field in ObjectClass with the tested object values static final String OBJECT_FIELD_NAME = setvalues001a.OBJECT_FIELD_NAME; + static final String FINAL_OBJECT_FIELD_NAME = setvalues001a.FINAL_OBJECT_FIELD_NAME; // usual scaffold objects ArgumentHandler argumentHandler = null; @@ -154,7 +159,7 @@ public int runIt(String argv[], PrintStream out) { log.display("Getting values of the static fields"); JDWP.Value targetValues[] = queryClassFieldValues(targetValuesClassID, targetValuesFieldIDs); - log.display(" got values: " + targetValues.length); + log.display(" got target values: " + targetValues.length); if (targetValues.length != count) { throw new Failure("Unexpected number of static fields values received: " + targetValues.length + "(expected: " + count + ")"); @@ -164,7 +169,7 @@ public int runIt(String argv[], PrintStream out) { log.display("Getting tested classID by signature:\n" + " " + TESTED_CLASS_SIGNATURE); long testedClassID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE); - log.display(" got classID: " + testedClassID); + log.display(" got tested classID: " + testedClassID); // query debugee for fieldIDs of tested class fields log.display("Getting fieldIDs for tested fields of the tested class"); @@ -175,6 +180,21 @@ public int runIt(String argv[], PrintStream out) { + testedFieldIDs.length + "(expected: " + count + ")"); } + // query debugee for classID of the tested final class + log.display("Getting tested final classID by signature:\n" + + " " + TESTED_FINAL_CLASS_SIGNATURE); + long testedFinalClassID = debugee.getReferenceTypeID(TESTED_FINAL_CLASS_SIGNATURE); + log.display(" got tested final classID: " + testedFinalClassID); + + // query debugee for fieldIDs of tested final class fields + log.display("Getting fieldIDs for tested fields of the tested final class"); + long testedFinalFieldIDs[] = queryClassFieldIDs(testedFinalClassID); + log.display(" got fields: " + testedFinalFieldIDs.length); + if (testedFinalFieldIDs.length != count) { + throw new Failure("Unexpected number of fields of tested final class received: " + + testedFinalFieldIDs.length + "(expected: " + count + ")"); + } + // query debugee for classID of the object class log.display("Getting object classID by signature:\n" + " " + OBJECT_CLASS_SIGNATURE); @@ -188,14 +208,24 @@ public int runIt(String argv[], PrintStream out) { OBJECT_FIELD_NAME, JDWP.Tag.OBJECT); log.display(" got objectID: " + objectID); - // perform testing JDWP command - log.display("\n>>> Testing JDWP command \n"); + // query debuggee for finalObjectID value from static field + log.display("Getting finalObjectID value from static field: " + + FINAL_OBJECT_FIELD_NAME); + long finalObjectID = queryObjectID(classID, + FINAL_OBJECT_FIELD_NAME, JDWP.Tag.OBJECT); + log.display(" got finalObjectID: " + finalObjectID); + + log.display("\n>>> Testing JDWP ObjectReference.SetValues command on tested class\n"); testCommand(objectID, testedFieldIDs, targetValues); - // check confirmation from debuggee that values have been set properly - log.display("\n>>> Checking that the values have been set properly \n"); + log.display("\n>>> Checking with the debuggee that the values have been set properly\n"); checkValuesChanged(); + log.display("\n>>> Testing JDWP ObjectReference.SetValues command on tested final class\n"); + testCommand(finalObjectID, testedFinalFieldIDs, targetValues); + + log.display("\n>>> Checking with JDWP ObjectReference.GetValues that the values have been set properly\n"); + checkJDWPValuesChanged(finalObjectID, testedFinalFieldIDs, targetValues); } finally { // quit debugee log.display("\n>>> Finishing test \n"); @@ -344,6 +374,43 @@ JDWP.Value[] queryClassFieldValues(long classID, long fieldIDs[]) { } } + /** + * Query debugee for values of the object fields. + */ + JDWP.Value[] queryObjectFieldValues(long objectID, long fieldIDs[]) { + // compose ReferenceType.Fields command packet + int count = fieldIDs.length; + CommandPacket command = new CommandPacket(JDWP.Command.ObjectReference.GetValues); + command.addObjectID(objectID); + command.addInt(count); + for (int i = 0; i < count; i++) { + command.addFieldID(fieldIDs[i]); + } + command.setLength(); + + // send the command and receive reply + ReplyPacket reply = debugee.receiveReplyFor(command); + + // extract values from the reply packet + try { + reply.resetPosition(); + + int valuesCount = reply.getInt(); + JDWP.Value values[] = new JDWP.Value[valuesCount]; + for (int i = 0; i < valuesCount; i++ ) { + JDWP.Value value = reply.getValue(); + values[i] = value; + } + return values; + } catch (BoundException e) { + log.complain("Unable to parse reply packet for ReferenceType.GetValues command:\n\t" + + e); + log.complain("Received reply packet:\n" + + reply); + throw new Failure("Error occured while getting fields values for objectID: " + objectID); + } + } + /** * Query debuggee for objectID value of static class field. */ @@ -440,7 +507,7 @@ void testCommand(long objectID, long fieldIDs[], JDWP.Value values[]) { } /** - * Check confiramtion from debuggee that values are changed. + * Check confirmation from debuggee that values are changed. */ void checkValuesChanged() { // send debugee signal RUN @@ -467,4 +534,39 @@ void checkValuesChanged() { } } + /** + * Check confirmation using JDWP ObjectReference.GetValues that the values are changed. + */ + void checkJDWPValuesChanged(long testedObjectID, long testedFieldIDs[], + JDWP.Value targetValues[]) { + // verify that JDWP ObjectReference.GetValues returns the expected values + int count = targetValues.length; + log.display("\n>>> Getting field values using JDWP ObjectReference.GetValues \n"); + JDWP.Value[] actualValues = queryObjectFieldValues(testedObjectID, testedFieldIDs); + log.display(" got actual values: " + actualValues.length); + if (actualValues.length != count) { + throw new Failure("Unexpected number of field values received: " + + actualValues.length + "(expected: " + count + ")"); + } + for (int i = 0; i < count; i++) { + log.display(" field #" + i +":"); + log.display(" fieldID: " + testedFieldIDs[i]); + + JDWP.Value actualValue = actualValues[i]; + JDWP.Value targetValue = targetValues[i]; + JDWP.UntaggedValue untaggedActualValue = + new JDWP.UntaggedValue(actualValue.getValue()); + JDWP.UntaggedValue untaggedTargetValue = + new JDWP.UntaggedValue(targetValue.getValue()); + log.display(" untaggedActualValue: " + untaggedActualValue.getValue()); + log.display(" untaggedTargetValue: " + untaggedTargetValue.getValue()); + if (!untaggedActualValue.getValue().equals(untaggedTargetValue.getValue())) { + log.complain("JDWP found a field that was not correctly set"); + success = false; + } + } + if (success) { + log.display("Verfied using JDWP ObjectReference.GetValues that all fields values have been correctly set"); + } + } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001a.java index 1814034cd58a..15771a9fc45d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ObjectReference/SetValues/setvalues001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ public class setvalues001a { public static final String OBJECT_FIELD_NAME = "object"; + public static final String FINAL_OBJECT_FIELD_NAME = "finalObject"; static ArgumentHandler argumentHandler = null; static Log log = null; @@ -58,6 +59,7 @@ public int runIt(String args[], PrintStream out) { OriginalValuesClass original = new OriginalValuesClass(); TargetValuesClass target = new TargetValuesClass(); ObjectClass.object = new TestedClass(); + ObjectClass.finalObject = new TestedFinalClass(); // send debugger signal READY log.display("Sending signal to debugger: " + setvalues001.READY); @@ -284,7 +286,7 @@ static boolean checkValues(TestedClass object) { } */ - // check taht no any changed value differs from target + // check that none of the changed values differs from target if (different > 0) { log.complain("Values of " + different + " fields have not been set correctly"); return false; @@ -294,7 +296,7 @@ static boolean checkValues(TestedClass object) { return true; } - // class with the original values of static fields + // class with the original values of instance fields public static class OriginalValuesClass { static final boolean booleanValue = true; static final byte byteValue = (byte)0x01; @@ -308,7 +310,7 @@ public static class OriginalValuesClass { static final Object objectValue = new OriginalValuesClass(); } - // class with the original values of static fields + // class with the target values of instance fields public static class TargetValuesClass { static final boolean booleanValue = false; static final byte byteValue = (byte)0x0F; @@ -322,7 +324,7 @@ public static class TargetValuesClass { static final Object objectValue = new TargetValuesClass(); } - // tested class with own static fields values + // tested class with own instance fields values public static class TestedClass { private boolean booleanValue = OriginalValuesClass.booleanValue; private byte byteValue = OriginalValuesClass.byteValue; @@ -336,10 +338,25 @@ public static class TestedClass { Object objectValue = OriginalValuesClass.objectValue; } - // class with static field with the tested object + // tested class with own instance final fields values + public static class TestedFinalClass { + private final boolean booleanValue = OriginalValuesClass.booleanValue; + private final byte byteValue = OriginalValuesClass.byteValue; + protected final char charValue = OriginalValuesClass.charValue; + protected final int intValue = OriginalValuesClass.intValue; + public final short shortValue = OriginalValuesClass.shortValue; + public final long longValue = OriginalValuesClass.longValue; + final float floatValue = OriginalValuesClass.floatValue; + final double doubleValue = OriginalValuesClass.doubleValue; + final String stringValue = OriginalValuesClass.stringValue; + final Object objectValue = OriginalValuesClass.objectValue; + } + + // class with static fields with the tested objects public static class ObjectClass { - // static field with the tested object + // static fields with the tested objects public static TestedClass object = null; + public static TestedFinalClass finalObject = null; } } From 42541685a975483557b643d7caa4e1254772fdaf Mon Sep 17 00:00:00 2001 From: john spurling Date: Wed, 26 Aug 2026 19:55:13 +0000 Subject: [PATCH 098/223] 8390874: MethodData::extra_data_lock memory leak Reviewed-by: shade, coleenp, vlivanov --- src/hotspot/share/oops/methodData.cpp | 9 + src/hotspot/share/oops/methodData.hpp | 2 +- .../TestMethodDataObjectMutexLeak.java | 187 ++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/profiling/TestMethodDataObjectMutexLeak.java diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index f3ff17cd9ca5..b871fd87831f 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1914,6 +1914,15 @@ void MethodData::deallocate_contents(ClassLoaderData* loader_data) { release_C_heap_structures(); } +void MethodData::release_C_heap_structures() { + // The class unloading protocol guarantees that this object is + // unreachable at this point, so no synchronization is necessary. + if (_extra_data_lock != nullptr) { + delete _extra_data_lock; + _extra_data_lock = nullptr; + } +} + #if INCLUDE_CDS void MethodData::remove_unshareable_info() { _extra_data_lock = nullptr; diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 19ea9ac3ea11..aa8c961b7c90 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -2701,7 +2701,7 @@ class MethodData : public Metadata { // Deallocation support void deallocate_contents(ClassLoaderData* loader_data); - void release_C_heap_structures() {} + void release_C_heap_structures(); // GC support void set_size(int object_size_in_bytes) { _size = object_size_in_bytes; } diff --git a/test/hotspot/jtreg/compiler/profiling/TestMethodDataObjectMutexLeak.java b/test/hotspot/jtreg/compiler/profiling/TestMethodDataObjectMutexLeak.java new file mode 100644 index 000000000000..8fe29f6822bf --- /dev/null +++ b/test/hotspot/jtreg/compiler/profiling/TestMethodDataObjectMutexLeak.java @@ -0,0 +1,187 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8390874 + * @summary Test that method unloading doesn't cause leaks of C heap allocated Mutexes in MethodData instances. + * + * @run main/othervm/timeout=600 -Xbatch + -XX:NativeMemoryTracking=summary -XX:+UnlockDiagnosticVMOptions -XX:MallocLimit=synchronization:8m -XX:-CreateCoredumpOnCrash + compiler.profiling.TestMethodDataObjectMutexLeak + */ + +package compiler.profiling; + +import java.io.IOException; +import java.io.InputStream; + +public class TestMethodDataObjectMutexLeak { + static final String CLASS_NAME = Burn.class.getName(); + static final byte[] BYTES; + + static { + try (InputStream in = TestMethodDataObjectMutexLeak.class.getResourceAsStream("/" + CLASS_NAME.replace('.', '/') + ".class")) { + BYTES = in.readAllBytes(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public static class Burn implements Runnable { + int x; + public void run() { + for (int i = 0; i < 300; i++) { + work01(i); + } + } + + public void work01(int i) { work02(i); } + public void work02(int i) { work03(i); } + public void work03(int i) { work04(i); } + public void work04(int i) { work05(i); } + public void work05(int i) { work06(i); } + public void work06(int i) { work07(i); } + public void work07(int i) { work08(i); } + public void work08(int i) { work09(i); } + public void work09(int i) { work10(i); } + public void work10(int i) { work11(i); } + public void work11(int i) { work12(i); } + public void work12(int i) { work13(i); } + public void work13(int i) { work14(i); } + public void work14(int i) { work15(i); } + public void work15(int i) { work16(i); } + public void work16(int i) { work17(i); } + public void work17(int i) { work18(i); } + public void work18(int i) { work19(i); } + public void work19(int i) { work20(i); } + public void work20(int i) { work21(i); } + public void work21(int i) { work22(i); } + public void work22(int i) { work23(i); } + public void work23(int i) { work24(i); } + public void work24(int i) { work25(i); } + public void work25(int i) { work26(i); } + public void work26(int i) { work27(i); } + public void work27(int i) { work28(i); } + public void work28(int i) { work29(i); } + public void work29(int i) { work30(i); } + public void work30(int i) { work31(i); } + public void work31(int i) { work32(i); } + public void work32(int i) { work33(i); } + public void work33(int i) { work34(i); } + public void work34(int i) { work35(i); } + public void work35(int i) { work36(i); } + public void work36(int i) { work37(i); } + public void work37(int i) { work38(i); } + public void work38(int i) { work39(i); } + public void work39(int i) { work40(i); } + public void work40(int i) { work41(i); } + public void work41(int i) { work42(i); } + public void work42(int i) { work43(i); } + public void work43(int i) { work44(i); } + public void work44(int i) { work45(i); } + public void work45(int i) { work46(i); } + public void work46(int i) { work47(i); } + public void work47(int i) { work48(i); } + public void work48(int i) { work49(i); } + public void work49(int i) { work50(i); } + public void work50(int i) { work51(i); } + public void work51(int i) { work52(i); } + public void work52(int i) { work53(i); } + public void work53(int i) { work54(i); } + public void work54(int i) { work55(i); } + public void work55(int i) { work56(i); } + public void work56(int i) { work57(i); } + public void work57(int i) { work58(i); } + public void work58(int i) { work59(i); } + public void work59(int i) { work60(i); } + public void work60(int i) { work61(i); } + public void work61(int i) { work62(i); } + public void work62(int i) { work63(i); } + public void work63(int i) { work64(i); } + public void work64(int i) { work65(i); } + public void work65(int i) { work66(i); } + public void work66(int i) { work67(i); } + public void work67(int i) { work68(i); } + public void work68(int i) { work69(i); } + public void work69(int i) { work70(i); } + public void work70(int i) { work71(i); } + public void work71(int i) { work72(i); } + public void work72(int i) { work73(i); } + public void work73(int i) { work74(i); } + public void work74(int i) { work75(i); } + public void work75(int i) { work76(i); } + public void work76(int i) { work77(i); } + public void work77(int i) { work78(i); } + public void work78(int i) { work79(i); } + public void work79(int i) { work80(i); } + public void work80(int i) { work81(i); } + public void work81(int i) { work82(i); } + public void work82(int i) { work83(i); } + public void work83(int i) { work84(i); } + public void work84(int i) { work85(i); } + public void work85(int i) { work86(i); } + public void work86(int i) { work87(i); } + public void work87(int i) { work88(i); } + public void work88(int i) { work89(i); } + public void work89(int i) { work90(i); } + public void work90(int i) { work91(i); } + public void work91(int i) { work92(i); } + public void work92(int i) { work93(i); } + public void work93(int i) { work94(i); } + public void work94(int i) { work95(i); } + public void work95(int i) { work96(i); } + public void work96(int i) { work97(i); } + public void work97(int i) { work98(i); } + public void work98(int i) { work99(i); } + public void work99(int i) { + x += i * x + 42; + } + } + + static class MyCL extends ClassLoader { + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.equals(CLASS_NAME)) { + Class c = defineClass(name, BYTES, 0, BYTES.length); + if (resolve) { + resolveClass(c); + } + return c; + } + return super.loadClass(name, resolve); + } + } + + public static void main(String[] args) throws Exception { + for (int t = 0; t < 30; t++) { + System.gc(); + System.out.println("Epoch " + t); + for (int i = 0; i < 100; i++) { + Class c = Class.forName(CLASS_NAME, true, new MyCL()); + Runnable r = (Runnable) c.getDeclaredConstructor().newInstance(); + r.run(); + } + } + System.out.println("Done."); + } +} From c86277f718dde7379a10f41d38c4265bde412f73 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 26 Aug 2026 20:14:19 +0000 Subject: [PATCH 099/223] 8390907: Genshen: Improve mark loop performance Reviewed-by: kdnilsen, shade --- .../gc/shenandoah/shenandoahAgeCensus.cpp | 36 +-------- .../gc/shenandoah/shenandoahAgeCensus.hpp | 4 +- .../shenandoah/shenandoahAgeCensus.inline.hpp | 62 +++++++++++++++ .../gc/shenandoah/shenandoahCardTable.cpp | 4 +- .../gc/shenandoah/shenandoahClosures.hpp | 21 +++++- .../shenandoah/shenandoahClosures.inline.hpp | 6 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 3 +- .../shenandoahGenerationalFullGC.cpp | 1 + .../share/gc/shenandoah/shenandoahHeap.cpp | 2 + .../share/gc/shenandoah/shenandoahHeap.hpp | 12 ++- .../gc/shenandoah/shenandoahHeap.inline.hpp | 29 ++++++- .../gc/shenandoah/shenandoahHeapRegion.hpp | 4 + .../shenandoah/shenandoahInPlacePromoter.cpp | 1 + .../share/gc/shenandoah/shenandoahMark.hpp | 2 +- .../gc/shenandoah/shenandoahMark.inline.hpp | 75 ++++++++++--------- .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.hpp | 6 +- .../shenandoahReferenceProcessor.cpp | 4 +- .../shenandoah/shenandoahScanRemembered.cpp | 14 +--- .../shenandoah/shenandoahScanRemembered.hpp | 6 +- .../shenandoahScanRemembered.inline.hpp | 15 +++- .../shenandoah/test_shenandoahAgeCensus.cpp | 2 +- 22 files changed, 203 insertions(+), 108 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.inline.hpp diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 8fa497802fde..3c23dd0bf233 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ */ #include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp" -#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "gc/shenandoah/shenandoahAgeCensus.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" ShenandoahAgeCensus::ShenandoahAgeCensus() @@ -82,38 +82,6 @@ ShenandoahAgeCensus::~ShenandoahAgeCensus() { } } -CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id) {) -NO_CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, size_t size, uint worker_id) {) - if (obj_age <= markWord::max_age) { - assert(obj_age < MAX_COHORTS && region_age < MAX_COHORTS, "Should have been tenured"); -#ifdef SHENANDOAH_CENSUS_NOISE - // Region ageing is stochastic and non-monotonic; this vitiates mortality - // demographics in ways that might defeat our algorithms. Marking may be a - // time when we might be able to correct this, but we currently do not do - // this. Like skipped statistics further below, we want to track the - // impact of this noise to see if this may be worthwhile. JDK-. - uint age = obj_age; - if (region_age > 0) { - add_aged(size, worker_id); // this tracking is coarse for now - age += region_age; - if (age >= MAX_COHORTS) { - age = (uint)(MAX_COHORTS - 1); // clamp - add_clamped(size, worker_id); - } - } - if (region_youth > 0) { // track object volume with retrograde age - add_young(size, worker_id); - } -#else // SHENANDOAH_CENSUS_NOISE - uint age = MIN2(obj_age + region_age, (uint)(MAX_COHORTS - 1)); // clamp -#endif // SHENANDOAH_CENSUS_NOISE - get_local_age_table(worker_id)->add(age, size); - } else { - // update skipped statistics - CENSUS_NOISE(add_skipped(size, worker_id);) - } -} - #ifdef SHENANDOAH_CENSUS_NOISE void ShenandoahAgeCensus::add_skipped(size_t size, uint worker_id) { _local_noise[worker_id].skipped += size; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 8cc8e31cf291..2d79eb559609 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -205,8 +205,8 @@ class ShenandoahAgeCensus: public CHeapObj { // Update the local age table for worker_id by size for // given obj_age, region_age, and region_youth - CENSUS_NOISE(void add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id);) - NO_CENSUS_NOISE(void add(uint obj_age, uint region_age, size_t size, uint worker_id);) + CENSUS_NOISE(inline void add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id);) + NO_CENSUS_NOISE(inline void add(uint obj_age, uint region_age, size_t size, uint worker_id);) #ifdef SHENANDOAH_CENSUS_NOISE // Update the local skip table for worker_id by size diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.inline.hpp new file mode 100644 index 000000000000..299b9a3f8b7a --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.inline.hpp @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_INLINE_HPP + +#include "gc/shenandoah/shenandoahAgeCensus.hpp" + +CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id) {) +NO_CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, size_t size, uint worker_id) {) + if (obj_age <= markWord::max_age) { + assert(obj_age < MAX_COHORTS && region_age < MAX_COHORTS, "Should have been tenured"); +#ifdef SHENANDOAH_CENSUS_NOISE + // Region ageing is stochastic and non-monotonic; this vitiates mortality + // demographics in ways that might defeat our algorithms. Marking may be a + // time when we might be able to correct this, but we currently do not do + // this. Like skipped statistics further below, we want to track the + // impact of this noise to see if this may be worthwhile. JDK-. + uint age = obj_age; + if (region_age > 0) { + add_aged(size, worker_id); // this tracking is coarse for now + age += region_age; + if (age >= MAX_COHORTS) { + age = (uint)(MAX_COHORTS - 1); // clamp + add_clamped(size, worker_id); + } + } + if (region_youth > 0) { // track object volume with retrograde age + add_young(size, worker_id); + } +#else // SHENANDOAH_CENSUS_NOISE + uint age = MIN2(obj_age + region_age, (uint)(MAX_COHORTS - 1)); // clamp +#endif // SHENANDOAH_CENSUS_NOISE + get_local_age_table(worker_id)->add(age, size); + } else { + // update skipped statistics + CENSUS_NOISE(add_skipped(size, worker_id);) + } +} + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp index e9e52475fb92..3ce54f9e3bd6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -96,7 +96,7 @@ bool ShenandoahCardTable::is_in_young(const void* obj) const { return ShenandoahHeap::heap()->is_in_young(obj); } -CardValue* ShenandoahCardTable::read_byte_for(const void* p) { +CardTable::CardValue* ShenandoahCardTable::read_byte_for(const void* p) { CardValue* result = &_read_byte_map_base[uintptr_t(p) >> _card_shift]; assert(result >= _read_byte_map && result < _read_byte_map + _byte_map_size, "out of bounds accessor for card marking array"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index eb40dfbd31d6..8b082b4127b0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -71,7 +71,7 @@ class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { bool _weak; protected: - template + template void work(T *p); public: @@ -96,7 +96,7 @@ class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { private: template ALWAYSINLINE - void do_oop_work(T* p) { work(p); } + void do_oop_work(T* p) { work(p); } public: ShenandoahMarkRefsClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q) : @@ -109,6 +109,23 @@ class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { void do_oop(oop* p) override { do_oop_work(p); } }; +class ShenandoahRedirtyCardsMarkClosure : public ShenandoahMarkRefsSuperClosure { +private: + template + ALWAYSINLINE + void do_oop_work(T* p) { work(p); } + +public: + ShenandoahRedirtyCardsMarkClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q) + : ShenandoahMarkRefsSuperClosure(q, rp, old_q) {} + + ALWAYSINLINE + void do_oop(narrowOop* p) override { do_oop_work(p); } + + ALWAYSINLINE + void do_oop(oop* p) override { do_oop_work(p); } +}; + class ShenandoahForwardedIsAliveClosure : public BoolObjectClosure { private: ShenandoahMarkingContext* const _mark_context; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index f57a9b209578..9beb47fa64a1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -76,10 +76,10 @@ ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToSc _mark_context(ShenandoahHeap::heap()->marking_context()), _weak(false) {} -template +template ALWAYSINLINE void ShenandoahMarkRefsSuperClosure::work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); + ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); } ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : @@ -229,7 +229,7 @@ inline void ShenandoahMarkUpdateRefsClosure::work(T* p) { _heap->non_conc_update_with_forwarded(p); // ...then do the usual thing - ShenandoahMarkRefsSuperClosure::work(p); + ShenandoahMarkRefsSuperClosure::work(p); } template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 9db0f6627055..346ecd121fdb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -24,14 +24,13 @@ * */ -#include "gc/shared/tlab_globals.hpp" #include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahAllocator.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 323453756838..7b59c10b15fe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -31,6 +31,7 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahScanRemembered.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index de660badd9ac..1411e7337d5f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -410,6 +410,7 @@ jint ShenandoahHeap::initialize() { _regions = NEW_C_HEAP_ARRAY(ShenandoahHeapRegion*, _num_regions, mtGC); _affiliations = NEW_C_HEAP_ARRAY(uint8_t, _num_regions, mtGC); + _biased_affiliations = _affiliations - (p2u(base()) >> ShenandoahHeapRegion::region_size_bytes_shift()); { ShenandoahHeapLocker locker(lock()); @@ -568,6 +569,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : _num_regions(0), _regions(nullptr), _affiliations(nullptr), + _biased_affiliations(nullptr), _gc_state_changed(false), _gc_no_progress_count(0), _cancel_requested_time(0), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f26bb0d80cc3..58ad8f46c058 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -287,6 +287,7 @@ class ShenandoahHeap : public CollectedHeap { size_t _num_regions; ShenandoahHeapRegion** _regions; uint8_t* _affiliations; // Holds array of enum ShenandoahAffiliation, including FREE status in non-generational mode + uint8_t* _biased_affiliations; public: @@ -634,6 +635,15 @@ class ShenandoahHeap : public CollectedHeap { inline bool is_in_young(const void* p) const; inline bool is_in_old(const void* p) const; + // Returns true if `maybe_old` is in old and `maybe_young` is in young + inline bool is_old_to_young(const void* maybe_old, oop maybe_young) const; + + // Returns false if `p` is not in the heap or does not have the given affiliation. + inline bool has_affiliation(const void* p, ShenandoahAffiliation affiliation) const; + + // Does not check that `obj` is in the heap (debug builds assert that `obj` is in the heap). + inline bool has_affiliation(oop obj, ShenandoahAffiliation affiliation) const; + // Returns true iff the young generation is being collected and the given pointer // is in the old generation. This is used to prevent the young collection from treating // such an object as unreachable. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 5642d73e7262..dfd7e722c9ee 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -361,11 +361,36 @@ inline bool ShenandoahHeap::is_in_active_generation(oop obj) const { } inline bool ShenandoahHeap::is_in_young(const void* p) const { - return is_in_reserved(p) && (region_affiliation(heap_region_index_containing(p)) == ShenandoahAffiliation::YOUNG_GENERATION); + return has_affiliation(p, YOUNG_GENERATION); } inline bool ShenandoahHeap::is_in_old(const void* p) const { - return is_in_reserved(p) && (region_affiliation(heap_region_index_containing(p)) == ShenandoahAffiliation::OLD_GENERATION); + return has_affiliation(p, OLD_GENERATION); +} + +inline bool ShenandoahHeap::is_old_to_young(const void* maybe_old, oop maybe_young) const { + if (maybe_young == nullptr) { + return false; + } + if (ShenandoahHeapRegion::is_in_same_region(maybe_old, maybe_young)) { + return false; + } + return has_affiliation(maybe_old, OLD_GENERATION) && has_affiliation(maybe_young, YOUNG_GENERATION); +} + +inline bool ShenandoahHeap::has_affiliation(const void* p, ShenandoahAffiliation affiliation) const { + if (!is_in_reserved(p)) { + return false; + } + + const size_t index = p2u(p) >> ShenandoahHeapRegion::region_size_bytes_shift(); + return AtomicAccess::load(_biased_affiliations + index) == affiliation; +} + +inline bool ShenandoahHeap::has_affiliation(oop obj, ShenandoahAffiliation affiliation) const { + assert(is_in_reserved(obj), "Expected decoded oop (" PTR_FORMAT ") to be in the heap", p2i(obj)); + const size_t index = p2u(obj) >> ShenandoahHeapRegion::region_size_bytes_shift(); + return AtomicAccess::load(_biased_affiliations + index) == affiliation; } inline bool ShenandoahHeap::is_in_old_during_young_collection(oop obj) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 98fc9040df96..8074aac151b3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -370,6 +370,10 @@ class ShenandoahHeapRegion { return _index; } + static bool is_in_same_region(const void* p, oop obj) { + return (((uintptr_t) p ^ cast_from_oop(obj)) >> region_size_bytes_shift()) == 0; + } + inline void save_top_before_promote(); inline HeapWord* get_top_before_promote() const { return _top_before_promoted; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp index 4a3c2b9f2e30..8b4c5291877b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp @@ -29,6 +29,7 @@ #include "gc/shenandoah/shenandoahInPlacePromoter.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahScanRemembered.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" ShenandoahInPlacePromotionPlanner::ShenandoahInPlacePromotionPlanner(const ShenandoahGenerationalHeap* heap) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index a2c363b21299..e67acccc8048 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -50,7 +50,7 @@ class ShenandoahMark: public StackObj { ShenandoahMark(ShenandoahGeneration* generation); public: - template + template ALWAYSINLINE static void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index d1bf28cc33c2..0e19f8fd4b4e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2015, 2022, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "gc/shenandoah/shenandoahMark.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" -#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "gc/shenandoah/shenandoahAgeCensus.inline.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" @@ -308,7 +308,7 @@ class ShenandoahSATBBufferClosure : public SATBBufferClosure { assert(size == 0 || !_heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded objects are not expected here"); for (size_t i = 0; i < size; ++i) { oop *p = (oop *) &buffer[i]; - ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, false); + ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, false); } } }; @@ -317,11 +317,11 @@ template bool ShenandoahMark::in_generation(ShenandoahHeap* const heap, oop obj) { // Each in-line expansion of in_generation() resolves GENERATION at compile time. if (GENERATION == YOUNG) { - return heap->is_in_young(obj); + return heap->has_affiliation(obj, YOUNG_GENERATION); } if (GENERATION == OLD) { - return heap->is_in_old(obj); + return heap->has_affiliation(obj, OLD_GENERATION); } assert((GENERATION == GLOBAL || GENERATION == NON_GEN), "Unexpected generation type"); @@ -329,51 +329,58 @@ bool ShenandoahMark::in_generation(ShenandoahHeap* const heap, oop obj) { return true; } -template +template void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { + static_assert(GENERATION != NON_GEN, "Should use the non-generational specialization"); + static_assert(!REDIRTY || GENERATION == YOUNG, "Redirty is only valid for young marking"); + // Note: This is a very hot code path, so the code should be conditional on GENERATION template // parameter where possible, in order to generate the most efficient code. - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); + if (CompressedOops::is_null(o)) { + return; + } - ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); - shenandoah_assert_not_forwarded(p, obj); - shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc()); - if (in_generation(heap, obj)) { - mark_ref(q, mark_context, weak, obj); - shenandoah_assert_marked(p, obj); - if (GENERATION == YOUNG && heap->is_in_old(p)) { - // Mark card as dirty because remembered set scanning still finds interesting pointer. - heap->old_generation()->mark_card_as_dirty((HeapWord*)p); - } else if (GENERATION == GLOBAL && heap->is_in_old(p) && heap->is_in_young(obj)) { - // Mark card as dirty because GLOBAL marking finds interesting pointer. - heap->old_generation()->mark_card_as_dirty((HeapWord*)p); - } - } else if (old_q != nullptr) { - // Young mark, bootstrapping old_q or concurrent with old_q marking. - mark_ref(old_q, mark_context, weak, obj); - shenandoah_assert_marked(p, obj); - } else if (GENERATION == OLD) { - // Old mark, found a young pointer. - if (heap->is_in(p)) { - assert(heap->is_in_young(obj), "Expected young object."); - heap->old_generation()->mark_card_as_dirty(p); - } + ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); + oop obj = CompressedOops::decode_not_null(o); + shenandoah_assert_not_forwarded(p, obj); + shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc()); + if (in_generation(heap, obj)) { + mark_ref(q, mark_context, weak, obj); + shenandoah_assert_marked(p, obj); + if (REDIRTY && heap->has_affiliation(p, OLD_GENERATION)) { + // We are redirtying the remembered set, the object iterator + // may visit class metadata that lives outside the heap so we cannot + // assume (or assert) that `p` is in old. + heap->old_generation()->mark_card_as_dirty(p); + } else if (GENERATION == YOUNG && !REDIRTY) { + assert(!heap->has_affiliation(p, OLD_GENERATION), "Young mark should not encounter pointers in old"); + } else if (GENERATION == GLOBAL && heap->is_old_to_young(p, obj)) { + // Mark card as dirty because GLOBAL marking finds interesting pointer. + heap->old_generation()->mark_card_as_dirty(p); + } + } else if (old_q != nullptr) { + // Young mark, bootstrapping old_q or concurrent with old_q marking. + mark_ref(old_q, mark_context, weak, obj); + shenandoah_assert_marked(p, obj); + } else if (GENERATION == OLD) { + // Old mark, found a young pointer. + if (heap->is_in_reserved(p)) { + assert(heap->has_affiliation(obj, YOUNG_GENERATION), "Expected young object."); + heap->old_generation()->mark_card_as_dirty(p); } } } template<> ALWAYSINLINE -void ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { +void ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { mark_non_generational_ref(p, q, mark_context, weak); } template<> ALWAYSINLINE -void ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { +void ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { mark_non_generational_ref(p, q, mark_context, weak); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 8d34937218ec..26e61d31fa81 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -800,7 +800,7 @@ void ShenandoahOldGeneration::clear_cards_for(ShenandoahHeapRegion* region) { _card_scan->mark_range_as_empty(region->bottom(), pointer_delta(region->end(), region->bottom())); } -void ShenandoahOldGeneration::mark_card_as_dirty(void* location) { +void ShenandoahOldGeneration::mark_card_as_dirty(void* location) const { _card_scan->mark_card_as_dirty((HeapWord*)location); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 3519303c3037..ba069d961f79 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -30,10 +30,10 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" -#include "gc/shenandoah/shenandoahScanRemembered.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" class LogStream; +class ShenandoahScanRemembered; class ShenandoahHeapRegion; class ShenandoahHeapRegionClosure; class ShenandoahOldHeuristics; @@ -193,7 +193,7 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { void clear_cards_for(ShenandoahHeapRegion* region); // Mark card for this location as dirty - void mark_card_as_dirty(void* location); + void mark_card_as_dirty(void* location) const; template class ShenandoahHeapRegionLambda : public ShenandoahHeapRegionClosure { @@ -343,7 +343,7 @@ class ShenandoahOldGeneration : public ShenandoahGeneration { size_t usage_trigger_threshold() const; - bool can_start_gc() { + bool can_start_gc() const { return _state == IDLE; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index c24735b92cf4..3bc0f050242f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Red Hat, Inc. and/or its affiliates. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -64,7 +64,7 @@ static void card_mark_barrier(T* field, oop value) { assert(ShenandoahCardBarrier, "Card-mark barrier should be on"); ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); assert(heap->is_in_or_null(value), "Should be in heap"); - if (heap->is_in_old(field) && heap->is_in_young(value)) { + if (heap->is_old_to_young(field, value)) { // For Shenandoah, each generation collects all the _referents_ that belong to the // collected generation. We can end up with discovered lists that contain a mixture // of old and young _references_. These references are linked together through the diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index c3a82b987e22..103c51db7741 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,12 +108,6 @@ bool ShenandoahDirectCardMarkRememberedSet::is_write_card_dirty(HeapWord* p) con return (bp[0] == CardTable::dirty_card_val()); } -void ShenandoahDirectCardMarkRememberedSet::mark_card_as_dirty(HeapWord* p) { - size_t index = card_index_for_addr(p); - CardValue* bp = &(_card_table->write_byte_map())[index]; - bp[0] = CardTable::dirty_card_val(); -} - void ShenandoahDirectCardMarkRememberedSet::mark_range_as_dirty(HeapWord* p, size_t num_heap_words) { CardValue* bp = &(_card_table->write_byte_map_base())[uintptr_t(p) >> _card_shift]; CardValue* end_bp = &(_card_table->write_byte_map_base())[uintptr_t(p + num_heap_words) >> _card_shift]; @@ -474,10 +468,6 @@ bool ShenandoahScanRemembered::is_card_dirty(HeapWord* p) { return _rs->is_card_dirty(p); } -void ShenandoahScanRemembered::mark_card_as_dirty(HeapWord* p) { - _rs->mark_card_as_dirty(p); -} - bool ShenandoahScanRemembered::is_write_card_dirty(HeapWord* p) { return _rs->is_write_card_dirty(p); } @@ -812,7 +802,7 @@ void ShenandoahScanRememberedTask::do_work(uint worker_id) { ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); ShenandoahObjToScanQueue* old = _old_queue_set == nullptr ? nullptr : _old_queue_set->queue(worker_id); - ShenandoahMarkRefsClosure cl(q, _rp, old); + ShenandoahRedirtyCardsMarkClosure cl(q, _rp, old); ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); ShenandoahScanRemembered* scanner = heap->old_generation()->card_scan(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 244ed7edd4c6..7178d8f2b5f2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -235,7 +235,8 @@ class ShenandoahDirectCardMarkRememberedSet: public CHeapObj { inline void mark_range_as_dirty(size_t card_index, size_t num_cards); inline bool is_card_dirty(HeapWord* p) const; inline bool is_write_card_dirty(HeapWord* p) const; - inline void mark_card_as_dirty(HeapWord* p); + inline void mark_card_as_dirty(HeapWord* p) const; + inline void mark_range_as_dirty(HeapWord* p, size_t num_heap_words); inline void mark_range_as_clean(HeapWord* p, size_t num_heap_words); @@ -782,7 +783,8 @@ class ShenandoahScanRemembered: public CHeapObj { bool is_write_card_dirty(size_t card_index); bool is_card_dirty(HeapWord* p); bool is_write_card_dirty(HeapWord* p); - void mark_card_as_dirty(HeapWord* p); + inline void mark_card_as_dirty(HeapWord* p) const; + void mark_range_as_dirty(HeapWord* p, size_t num_heap_words); void mark_range_as_clean(HeapWord* p, size_t num_heap_words); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp index 0948b737c776..64624faeb7d2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,6 @@ #include "gc/shenandoah/shenandoahScanRemembered.hpp" -#include "gc/shared/collectorCounters.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahCardStats.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" @@ -37,9 +35,12 @@ #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" -#include "oops/objArrayOop.hpp" #include "oops/oop.hpp" +void ShenandoahScanRemembered::mark_card_as_dirty(HeapWord* p) const { + _rs->mark_card_as_dirty(p); +} + // Process all objects starting within count clusters beginning with first_cluster and for which the start address is // less than end_of_range. For any non-array object whose header lies on a dirty card, scan the entire object, // even if its end reaches beyond end_of_range. Object arrays, on the other hand, are precisely dirtied and @@ -427,4 +428,10 @@ inline bool ShenandoahRegionChunkIterator::next(struct ShenandoahRegionChunk *as return true; } +void ShenandoahDirectCardMarkRememberedSet::mark_card_as_dirty(HeapWord* p) const { + size_t index = card_index_for_addr(p); + CardValue* bp = &(_card_table->write_byte_map())[index]; + bp[0] = CardTable::dirty_card_val(); +} + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHSCANREMEMBEREDINLINE_HPP diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp index 0b89c59634ac..9189e5af456e 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp @@ -22,7 +22,7 @@ * */ -#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "gc/shenandoah/shenandoahAgeCensus.inline.hpp" #include "unittest.hpp" class ShenandoahAgeCensusTest : public ::testing::Test { From 5e150f7439333a8d476cac350d41224e0d6d02ab Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 26 Aug 2026 21:27:32 +0000 Subject: [PATCH 100/223] 8390765: [PPC64] AES Crypto intrinsics may access memory beyond the key array Reviewed-by: dbriemann, amitkumar, sroy --- src/hotspot/cpu/ppc/assembler_ppc.hpp | 22 ++ src/hotspot/cpu/ppc/assembler_ppc.inline.hpp | 110 +++++++ src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 319 ++++--------------- 3 files changed, 190 insertions(+), 261 deletions(-) diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index 77c7f63cd062..e6a78485411e 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -539,6 +539,10 @@ class Assembler : public AbstractAssembler { STXVL_OPCODE = (31u << OPCODE_SHIFT | 397u << 1), LXVD2X_OPCODE = (31u << OPCODE_SHIFT | 844u << 1), STXVD2X_OPCODE = (31u << OPCODE_SHIFT | 972u << 1), + LXVW4X_OPCODE = (31u << OPCODE_SHIFT | 780u << 1), + STXVW4X_OPCODE = (31u << OPCODE_SHIFT | 908u << 1), + LXVB16X_OPCODE = (31u << OPCODE_SHIFT | 876u << 1), + STXVB16X_OPCODE= (31u << OPCODE_SHIFT | 1004u << 1), MTVSRD_OPCODE = (31u << OPCODE_SHIFT | 179u << 1), MTVSRDD_OPCODE = (31u << OPCODE_SHIFT | 435u << 1), MTVSRWZ_OPCODE = (31u << OPCODE_SHIFT | 243u << 1), @@ -2386,8 +2390,17 @@ class Assembler : public AbstractAssembler { inline void lxvd2x( VectorSRegister d, Register a, Register b); inline void stxvd2x( VectorSRegister d, Register a); inline void stxvd2x( VectorSRegister d, Register a, Register b); + inline void lxvw4x( VectorSRegister d, Register a); + inline void lxvw4x( VectorSRegister d, Register a, Register b); + inline void stxvw4x( VectorSRegister d, Register a); + inline void stxvw4x( VectorSRegister d, Register a, Register b); // Power9 + inline void lxvb16x( VectorSRegister d, Register a); + inline void lxvb16x( VectorSRegister d, Register a, Register b); + inline void stxvb16x( VectorSRegister d, Register a); + inline void stxvb16x( VectorSRegister d, Register a, Register b); + inline void lxv( VectorSRegister d, int si16, Register a); inline void stxv( VectorSRegister d, int si16, Register a); inline void lxvx( VectorSRegister d, Register a, Register b); @@ -2590,6 +2603,15 @@ class Assembler : public AbstractAssembler { inline void vec_perm(VectorRegister first_dest, VectorRegister second, VectorRegister perm); inline void vec_perm(VectorRegister dest, VectorRegister first, VectorRegister second, VectorRegister perm); + // Load/Store unaligned vectors with offs (multiple of 16). Byte versions require vp for Power8 LE. + inline void load_byte_vector_unaligned(VectorRegister dest, int offs, Register base, Register tmp, + VectorRegister vp); // vp should be pre-computed (see generator below) + inline void store_byte_vector_unaligned(VectorRegister val, int offs, Register base, Register tmp, + VectorRegister vp, VectorRegister vtmp = vnoreg); // clobbers val if no vtmp provided + inline void compute_vp_for_byte_vector_unaligned(VectorRegister dest, VectorRegister vtmp); + inline void load_word_vector_unaligned(VectorRegister dest, int offs, Register base, Register tmp); + inline void store_word_vector_unaligned(VectorRegister val, int offs, Register base, Register tmp); + // RegisterOrConstant versions. // These emitters choose between the versions using two registers and // those with register and immediate, depending on the content of roc. diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index 22b9e268dcdf..7929e895923b 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -856,6 +856,14 @@ inline void Assembler::lxvd2x( VectorSRegister d, Register s1) { e inline void Assembler::lxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra(0) | rb(s1)); } inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::lxvw4x( VectorSRegister d, Register s1) { emit_int32( LXVW4X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } +inline void Assembler::lxvw4x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVW4X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::stxvw4x( VectorSRegister d, Register s1) { emit_int32( STXVW4X_OPCODE | vsrs(d) | ra(0) | rb(s1)); } +inline void Assembler::stxvw4x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVW4X_OPCODE | vsrs(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::lxvb16x( VectorSRegister d, Register s1) { emit_int32( LXVB16X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } +inline void Assembler::lxvb16x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVB16X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::stxvb16x(VectorSRegister d, Register s1) { emit_int32( STXVB16X_OPCODE| vsrs(d) | ra(0) | rb(s1)); } +inline void Assembler::stxvb16x(VectorSRegister d, Register s1, Register s2) { emit_int32( STXVB16X_OPCODE| vsrs(d) | ra0mem(s1) | rb(s2)); } inline void Assembler::mtvsrd( VectorSRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d) | ra(a)); } inline void Assembler::mtvsrdd( VectorSRegister d, Register a, Register b) { emit_int32( MTVSRDD_OPCODE | vsrt(d) | ra(a) | rb(b)); } inline void Assembler::mfvsrd( Register d, VectorSRegister a) { emit_int32( MFVSRD_OPCODE | vsrs(a) | ra(d)); } @@ -1232,6 +1240,108 @@ inline void Assembler::vec_perm(VectorRegister dest, VectorRegister first, Vecto #endif } +inline void Assembler::load_byte_vector_unaligned(VectorRegister dest, int offs, Register base, Register tmp, + VectorRegister vp) { + VectorSRegister vsr = dest->to_vsr(); + if (PowerArchitecturePPC64 >= 9) { +#if !defined(VM_LITTLE_ENDIAN) + lxv(vsr, offs, base); // all vector load/store instructions use the same byte order on BE +#else + if (offs == 0) { + lxvb16x(vsr, base); + } else { + li(tmp, offs); + lxvb16x(vsr, base, tmp); + } +#endif + } else { // Power8 only supports very limited instructions + if (offs == 0) { + lxvd2x(vsr, base); + } else { + li(tmp, offs); + lxvd2x(vsr, base, tmp); + } +#if defined(VM_LITTLE_ENDIAN) + // need to swap bytes in both double-words + vperm(dest, dest, dest, vp); +#endif + } +} + +inline void Assembler::store_byte_vector_unaligned(VectorRegister val, int offs, Register base, Register tmp, + VectorRegister vp, VectorRegister vtmp) { + VectorSRegister vsr = val->to_vsr(); + if (PowerArchitecturePPC64 >= 9) { +#if !defined(VM_LITTLE_ENDIAN) + stxv(vsr, offs, base); // all vector load/store instructions use the same byte order on BE +#else + if (offs == 0) { + stxvb16x(vsr, base); + } else { + li(tmp, offs); + stxvb16x(vsr, base, tmp); + } +#endif + } else { // Power8 only supports very limited instructions +#if defined(VM_LITTLE_ENDIAN) + // need to swap bytes in both double-words + if (vtmp != vnoreg) { + vperm(vtmp, val, val, vp); + vsr = vtmp->to_vsr(); + } else { + vperm(val, val, val, vp); // clobbers val! + } +#endif + if (offs == 0) { + stxvd2x(vsr, base); + } else { + li(tmp, offs); + stxvd2x(vsr, base, tmp); + } + } +} + +inline void Assembler::compute_vp_for_byte_vector_unaligned(VectorRegister dest, VectorRegister vtmp) { +#if defined(VM_LITTLE_ENDIAN) + if (PowerArchitecturePPC64 < 9) { + li(R0, 0); + vspltisb(vtmp, 7); // vtmp = [7, ..., 7] + lvsl(dest, R0); // dest = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + vxor(dest, dest, vtmp); // dest = [7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8] + } +#endif +} + +inline void Assembler::load_word_vector_unaligned(VectorRegister dest, int offs, Register base, Register tmp) { + VectorSRegister vsr = dest->to_vsr(); +#if !defined(VM_LITTLE_ENDIAN) + if (PowerArchitecturePPC64 >= 9) { + lxv(vsr, offs, base); // all vector load/store instructions use the same byte order on BE + } else +#endif + if (offs == 0) { + lxvw4x(vsr, base); + } else { + li(tmp, offs); + lxvw4x(vsr, base, tmp); + } +} + +inline void Assembler::store_word_vector_unaligned(VectorRegister val, int offs, Register base, Register tmp) { + VectorSRegister vsr = val->to_vsr(); +#if !defined(VM_LITTLE_ENDIAN) + if (PowerArchitecturePPC64 >= 9) { + stxv(vsr, offs, base); // all vector load/store instructions use the same byte order on BE + } else +#endif + if (offs == 0) { + stxvw4x(vsr, base); + } else { + li(tmp, offs); + stxvw4x(vsr, base, tmp); + } +} + inline void Assembler::load_const(Register d, void* x, Register tmp) { load_const(d, (long)x, tmp); } diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index c1a6b54df0bf..9f30dde1103f 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -2781,10 +2781,8 @@ class StubGenerator: public StubCodeGenerator { Register to = R4_ARG2; // destination array address Register key = R5_ARG3; // round key array - Register keylen = R8; - Register temp = R9; - Register keypos = R10; - Register fifteen = R12; + Register keylen = R6; + Register tmp = R7; VectorRegister vRet = VR0; @@ -2793,68 +2791,27 @@ class StubGenerator: public StubCodeGenerator { VectorRegister vKey3 = VR3; VectorRegister vKey4 = VR4; - VectorRegister fromPerm = VR5; - VectorRegister keyPerm = VR6; - VectorRegister toPerm = VR7; - VectorRegister fSplt = VR8; + VectorRegister vp = VR6; // permute vector for byte vector accesses on P8 LE - VectorRegister vTmp1 = VR9; - VectorRegister vTmp2 = VR10; - VectorRegister vTmp3 = VR11; - VectorRegister vTmp4 = VR12; - - __ li (fifteen, 15); + __ compute_vp_for_byte_vector_unaligned(vp, /*temp*/ vRet); // load unaligned from[0-15] to vRet - __ lvx (vRet, from); - __ lvx (vTmp1, fifteen, from); - __ lvsl (fromPerm, from); -#ifdef VM_LITTLE_ENDIAN - __ vspltisb (fSplt, 0x0f); - __ vxor (fromPerm, fromPerm, fSplt); -#endif - __ vperm (vRet, vRet, vTmp1, fromPerm); + __ load_byte_vector_unaligned(vRet, 0, from, tmp, vp); + + // load the 1st round key to vKey1 + __ load_word_vector_unaligned(vKey1, 0, key, tmp); // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); - // to load keys - __ load_perm (keyPerm, key); -#ifdef VM_LITTLE_ENDIAN - __ vspltisb (vTmp2, -16); - __ vrld (keyPerm, keyPerm, vTmp2); - __ vrld (keyPerm, keyPerm, vTmp2); - __ vsldoi (keyPerm, keyPerm, keyPerm, 8); -#endif - - // load the 1st round key to vTmp1 - __ lvx (vTmp1, key); - __ li (keypos, 16); - __ lvx (vKey1, keypos, key); - __ vec_perm (vTmp1, vKey1, keyPerm); - // 1st round - __ vxor (vRet, vRet, vTmp1); - - // load the 2nd round key to vKey1 - __ li (keypos, 32); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vKey2, keyPerm); - - // load the 3rd round key to vKey2 - __ li (keypos, 48); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, keyPerm); - - // load the 4th round key to vKey3 - __ li (keypos, 64); - __ lvx (vKey4, keypos, key); - __ vec_perm (vKey3, vKey4, keyPerm); + __ vxor (vRet, vRet, vKey1); - // load the 5th round key to vKey4 - __ li (keypos, 80); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey4, vTmp1, keyPerm); + // load the 2nd - 5th round key to vKey1 - vKey4 + __ load_word_vector_unaligned(vKey1, 16, key, tmp); + __ load_word_vector_unaligned(vKey2, 32, key, tmp); + __ load_word_vector_unaligned(vKey3, 48, key, tmp); + __ load_word_vector_unaligned(vKey4, 64, key, tmp); // 2nd - 5th rounds __ vcipher (vRet, vRet, vKey1); @@ -2862,25 +2819,11 @@ class StubGenerator: public StubCodeGenerator { __ vcipher (vRet, vRet, vKey3); __ vcipher (vRet, vRet, vKey4); - // load the 6th round key to vKey1 - __ li (keypos, 96); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); - - // load the 7th round key to vKey2 - __ li (keypos, 112); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, keyPerm); - - // load the 8th round key to vKey3 - __ li (keypos, 128); - __ lvx (vKey4, keypos, key); - __ vec_perm (vKey3, vKey4, keyPerm); - - // load the 9th round key to vKey4 - __ li (keypos, 144); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey4, vTmp1, keyPerm); + // load the 6th - 9th round key to vKey1 - vKey4 + __ load_word_vector_unaligned(vKey1, 80, key, tmp); + __ load_word_vector_unaligned(vKey2, 96, key, tmp); + __ load_word_vector_unaligned(vKey3, 112, key, tmp); + __ load_word_vector_unaligned(vKey4, 128, key, tmp); // 6th - 9th rounds __ vcipher (vRet, vRet, vKey1); @@ -2888,15 +2831,9 @@ class StubGenerator: public StubCodeGenerator { __ vcipher (vRet, vRet, vKey3); __ vcipher (vRet, vRet, vKey4); - // load the 10th round key to vKey1 - __ li (keypos, 160); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); - - // load the 11th round key to vKey2 - __ li (keypos, 176); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey2, vTmp1, keyPerm); + // load the 10th - 11th round key to vKey1 - vKey2 + __ load_word_vector_unaligned(vKey1, 144, key, tmp); + __ load_word_vector_unaligned(vKey2, 160, key, tmp); // if all round keys are loaded, skip next 4 rounds __ cmpwi (CR0, keylen, 44); @@ -2906,15 +2843,9 @@ class StubGenerator: public StubCodeGenerator { __ vcipher (vRet, vRet, vKey1); __ vcipher (vRet, vRet, vKey2); - // load the 12th round key to vKey1 - __ li (keypos, 192); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); - - // load the 13th round key to vKey2 - __ li (keypos, 208); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey2, vTmp1, keyPerm); + // load the 12th - 13th round key to vKey1 - vKey2 + __ load_word_vector_unaligned(vKey1, 176, key, tmp); + __ load_word_vector_unaligned(vKey2, 192, key, tmp); // if all round keys are loaded, skip next 2 rounds __ cmpwi (CR0, keylen, 52); @@ -2929,15 +2860,9 @@ class StubGenerator: public StubCodeGenerator { __ vcipher (vRet, vRet, vKey1); __ vcipher (vRet, vRet, vKey2); - // load the 14th round key to vKey1 - __ li (keypos, 224); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vTmp1, vKey2, keyPerm); - - // load the 15th round key to vKey2 - __ li (keypos, 240); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey2, vTmp1, keyPerm); + // load the 14th - 15th round key to vKey1 - vKey2 + __ load_word_vector_unaligned(vKey1, 208, key, tmp); + __ load_word_vector_unaligned(vKey2, 224, key, tmp); __ bind(L_doLast); @@ -2945,23 +2870,8 @@ class StubGenerator: public StubCodeGenerator { __ vcipher (vRet, vRet, vKey1); __ vcipherlast (vRet, vRet, vKey2); -#ifdef VM_LITTLE_ENDIAN - // toPerm = 0x0F0E0D0C0B0A09080706050403020100 - __ lvsl (toPerm, keypos); // keypos is a multiple of 16 - __ vxor (toPerm, toPerm, fSplt); - - // Swap Bytes - __ vperm (vRet, vRet, vRet, toPerm); -#endif - // store result (unaligned) - // Note: We can't use a read-modify-write sequence which touches additional Bytes. - Register lo = temp, hi = fifteen; // Reuse - __ vsldoi (vTmp1, vRet, vRet, 8); - __ mfvrd (hi, vRet); - __ mfvrd (lo, vTmp1); - __ std (hi, 0 LITTLE_ENDIAN_ONLY(+ 8), to); - __ std (lo, 0 BIG_ENDIAN_ONLY(+ 8), to); + __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp); __ blr(); @@ -2989,10 +2899,8 @@ class StubGenerator: public StubCodeGenerator { Register to = R4_ARG2; // destination array address Register key = R5_ARG3; // round key array - Register keylen = R8; - Register temp = R9; - Register keypos = R10; - Register fifteen = R12; + Register keylen = R6; + Register tmp = R7; VectorRegister vRet = VR0; @@ -3002,41 +2910,16 @@ class StubGenerator: public StubCodeGenerator { VectorRegister vKey4 = VR4; VectorRegister vKey5 = VR5; - VectorRegister fromPerm = VR6; - VectorRegister keyPerm = VR7; - VectorRegister toPerm = VR8; - VectorRegister fSplt = VR9; - - VectorRegister vTmp1 = VR10; - VectorRegister vTmp2 = VR11; - VectorRegister vTmp3 = VR12; - VectorRegister vTmp4 = VR13; + VectorRegister vp = VR6; // permute vector for byte vector accesses on P8 LE - __ li (fifteen, 15); + __ compute_vp_for_byte_vector_unaligned(vp, /*temp*/ vRet); // load unaligned from[0-15] to vRet - __ lvx (vRet, from); - __ lvx (vTmp1, fifteen, from); - __ lvsl (fromPerm, from); -#ifdef VM_LITTLE_ENDIAN - __ vspltisb (fSplt, 0x0f); - __ vxor (fromPerm, fromPerm, fSplt); -#endif - __ vperm (vRet, vRet, vTmp1, fromPerm); // align [and byte swap in LE] + __ load_byte_vector_unaligned(vRet, 0, from, tmp, vp); // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); - // to load keys - __ load_perm (keyPerm, key); -#ifdef VM_LITTLE_ENDIAN - __ vxor (vTmp2, vTmp2, vTmp2); - __ vspltisb (vTmp2, -16); - __ vrld (keyPerm, keyPerm, vTmp2); - __ vrld (keyPerm, keyPerm, vTmp2); - __ vsldoi (keyPerm, keyPerm, keyPerm, 8); -#endif - __ cmpwi (CR0, keylen, 44); __ beq (CR0, L_do44); @@ -3048,32 +2931,12 @@ class StubGenerator: public StubCodeGenerator { __ bne (CR0, L_error); #endif - // load the 15th round key to vKey1 - __ li (keypos, 240); - __ lvx (vKey1, keypos, key); - __ li (keypos, 224); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vKey2, vKey1, keyPerm); - - // load the 14th round key to vKey2 - __ li (keypos, 208); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - - // load the 13th round key to vKey3 - __ li (keypos, 192); - __ lvx (vKey4, keypos, key); - __ vec_perm (vKey3, vKey4, vKey3, keyPerm); - - // load the 12th round key to vKey4 - __ li (keypos, 176); - __ lvx (vKey5, keypos, key); - __ vec_perm (vKey4, vKey5, vKey4, keyPerm); - - // load the 11th round key to vKey5 - __ li (keypos, 160); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); + // load the 15th - 11th round key to vKey1 - vKey5 + __ load_word_vector_unaligned(vKey1, 224, key, tmp); + __ load_word_vector_unaligned(vKey2, 208, key, tmp); + __ load_word_vector_unaligned(vKey3, 192, key, tmp); + __ load_word_vector_unaligned(vKey4, 176, key, tmp); + __ load_word_vector_unaligned(vKey5, 160, key, tmp); // 1st - 5th rounds __ vxor (vRet, vRet, vKey1); @@ -3087,22 +2950,10 @@ class StubGenerator: public StubCodeGenerator { __ align(32); __ bind (L_do52); - // load the 13th round key to vKey1 - __ li (keypos, 208); - __ lvx (vKey1, keypos, key); - __ li (keypos, 192); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vKey2, vKey1, keyPerm); - - // load the 12th round key to vKey2 - __ li (keypos, 176); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - - // load the 11th round key to vKey3 - __ li (keypos, 160); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey3, vTmp1, vKey3, keyPerm); + // load the 13th - 11th round key to vKey1 - vKey3 + __ load_word_vector_unaligned(vKey1, 192, key, tmp); + __ load_word_vector_unaligned(vKey2, 176, key, tmp); + __ load_word_vector_unaligned(vKey3, 160, key, tmp); // 1st - 3rd rounds __ vxor (vRet, vRet, vKey1); @@ -3115,41 +2966,19 @@ class StubGenerator: public StubCodeGenerator { __ bind (L_do44); // load the 11th round key to vKey1 - __ li (keypos, 176); - __ lvx (vKey1, keypos, key); - __ li (keypos, 160); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey1, vTmp1, vKey1, keyPerm); + __ load_word_vector_unaligned(vKey1, 160, key, tmp); // 1st round __ vxor (vRet, vRet, vKey1); __ bind (L_doLast); - // load the 10th round key to vKey1 - __ li (keypos, 144); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vKey2, vTmp1, keyPerm); - - // load the 9th round key to vKey2 - __ li (keypos, 128); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - - // load the 8th round key to vKey3 - __ li (keypos, 112); - __ lvx (vKey4, keypos, key); - __ vec_perm (vKey3, vKey4, vKey3, keyPerm); - - // load the 7th round key to vKey4 - __ li (keypos, 96); - __ lvx (vKey5, keypos, key); - __ vec_perm (vKey4, vKey5, vKey4, keyPerm); - - // load the 6th round key to vKey5 - __ li (keypos, 80); - __ lvx (vTmp1, keypos, key); - __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); + // load the 10th - 6th round key to vKey1 - vKey5 + __ load_word_vector_unaligned(vKey1, 144, key, tmp); + __ load_word_vector_unaligned(vKey2, 128, key, tmp); + __ load_word_vector_unaligned(vKey3, 112, key, tmp); + __ load_word_vector_unaligned(vKey4, 96, key, tmp); + __ load_word_vector_unaligned(vKey5, 80, key, tmp); // last 10th - 6th rounds __ vncipher (vRet, vRet, vKey1); @@ -3158,29 +2987,12 @@ class StubGenerator: public StubCodeGenerator { __ vncipher (vRet, vRet, vKey4); __ vncipher (vRet, vRet, vKey5); - // load the 5th round key to vKey1 - __ li (keypos, 64); - __ lvx (vKey2, keypos, key); - __ vec_perm (vKey1, vKey2, vTmp1, keyPerm); - - // load the 4th round key to vKey2 - __ li (keypos, 48); - __ lvx (vKey3, keypos, key); - __ vec_perm (vKey2, vKey3, vKey2, keyPerm); - - // load the 3rd round key to vKey3 - __ li (keypos, 32); - __ lvx (vKey4, keypos, key); - __ vec_perm (vKey3, vKey4, vKey3, keyPerm); - - // load the 2nd round key to vKey4 - __ li (keypos, 16); - __ lvx (vKey5, keypos, key); - __ vec_perm (vKey4, vKey5, vKey4, keyPerm); - - // load the 1st round key to vKey5 - __ lvx (vTmp1, key); - __ vec_perm (vKey5, vTmp1, vKey5, keyPerm); + // load the 5th - 1st round key to vKey1 - vKey5 + __ load_word_vector_unaligned(vKey1, 64, key, tmp); + __ load_word_vector_unaligned(vKey2, 48, key, tmp); + __ load_word_vector_unaligned(vKey3, 32, key, tmp); + __ load_word_vector_unaligned(vKey4, 16, key, tmp); + __ load_word_vector_unaligned(vKey5, 0, key, tmp); // last 5th - 1th rounds __ vncipher (vRet, vRet, vKey1); @@ -3189,23 +3001,8 @@ class StubGenerator: public StubCodeGenerator { __ vncipher (vRet, vRet, vKey4); __ vncipherlast (vRet, vRet, vKey5); -#ifdef VM_LITTLE_ENDIAN - // toPerm = 0x0F0E0D0C0B0A09080706050403020100 - __ lvsl (toPerm, keypos); // keypos is a multiple of 16 - __ vxor (toPerm, toPerm, fSplt); - - // Swap Bytes - __ vperm (vRet, vRet, vRet, toPerm); -#endif - // store result (unaligned) - // Note: We can't use a read-modify-write sequence which touches additional Bytes. - Register lo = temp, hi = fifteen; // Reuse - __ vsldoi (vTmp1, vRet, vRet, 8); - __ mfvrd (hi, vRet); - __ mfvrd (lo, vTmp1); - __ std (hi, 0 LITTLE_ENDIAN_ONLY(+ 8), to); - __ std (lo, 0 BIG_ENDIAN_ONLY(+ 8), to); + __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp); __ blr(); From 720b50d77b6b40df953f19bb0b8ed18755064cdf Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 27 Aug 2026 01:41:59 +0000 Subject: [PATCH 101/223] 8385672: SunEC NONEwithECDSA Signature.update(ByteBuffer) rejects an input of exactly 64 bytes, while update(byte[]) accepts it Reviewed-by: weijun, djelinski --- .../sun/security/ec/ECDSASignature.java | 8 +- .../security/ec/NONEwithECDSAOffsetTest.java | 114 ++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 test/jdk/sun/security/ec/NONEwithECDSAOffsetTest.java diff --git a/src/java.base/share/classes/sun/security/ec/ECDSASignature.java b/src/java.base/share/classes/sun/security/ec/ECDSASignature.java index 029affbac3d4..a3226889a90d 100644 --- a/src/java.base/share/classes/sun/security/ec/ECDSASignature.java +++ b/src/java.base/share/classes/sun/security/ec/ECDSASignature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,9 @@ protected void engineUpdate(byte b) throws SignatureException { @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { - if (offset >= precomputedDigest.length) { + // Check capacity. If precomputedDigest is already full, this + // condition effectively becomes 'len > -1' and will always be true + if (len > precomputedDigest.length - offset) { offset = RAW_ECDSA_MAX + 1; return; } @@ -172,7 +174,7 @@ protected void engineUpdate(ByteBuffer byteBuffer) { if (len <= 0) { return; } - if (len >= precomputedDigest.length - offset) { + if (len > precomputedDigest.length - offset) { offset = RAW_ECDSA_MAX + 1; return; } diff --git a/test/jdk/sun/security/ec/NONEwithECDSAOffsetTest.java b/test/jdk/sun/security/ec/NONEwithECDSAOffsetTest.java new file mode 100644 index 000000000000..c4a76b2f2767 --- /dev/null +++ b/test/jdk/sun/security/ec/NONEwithECDSAOffsetTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.ByteBuffer; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; + +import jtreg.SkippedException; + +/* + * @test + * @bug 8385672 + * @summary This test validates the length checks in SunEC's NONEwithECDSA + * implementation + * @library /test/lib/ + */ + +public class NONEwithECDSAOffsetTest { + + private static Signature s; + private static PrivateKey pk; + + public static void main(String[] args) throws Exception { + Provider prov = Security.getProvider("SunEC"); + if (prov == null) { + throw new SkippedException("Skip test - no SunEC provider found"); + } + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", prov); + kpg.initialize(new ECGenParameterSpec("secp521r1")); + pk = kpg.generateKeyPair().getPrivate(); + s = Signature.getInstance("NONEwithECDSA", prov); + + test(48, true); + test(64, true); + test(65, false); + } + + private static void test(int dataLen, boolean shouldPass) throws Exception { + System.out.println("Testing " + dataLen + ", shouldPass = " + + shouldPass); + byte[] data = new byte[dataLen]; + Arrays.fill(data, (byte) dataLen); + + int testNum = 1; + boolean done = false; + while (!done) { + String testId = String.format("Test#%d", testNum); + s.initSign(pk); + try { + switch (testNum++) { + case 1: // update(byte) + byte i = 0; + while (i++ < dataLen) { + s.update(i); + } + break; + case 2: // update(byte[]) + s.update(data); + break; + case 3: // update(byte[], int, int) + int firstPart = data.length/2; + s.update(data, 0, firstPart); + s.update(data, firstPart, data.length - firstPart); + break; + case 4: // update(ByteBuffer) + s.update(ByteBuffer.wrap(data)); + done = true; + break; + default: + throw new AssertionError("Error: Unsupported testNum" + + testNum); + } + s.sign(); + if (!shouldPass) { + done = true; + throw new AssertionError(testId + + " should throw SignatureException"); + } + } catch (SignatureException se) { + if (shouldPass) { + done = true; + throw new AssertionError(testId + + ": Unexpected SignatureException", se); + } + } + } + } +} From 8df41569c10134f1a97d59def2b37f4d4f11ac62 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 27 Aug 2026 05:36:53 +0000 Subject: [PATCH 102/223] 8376968: Signal handling: JNI_FastGetField stub search may be invoked too eagerly Reviewed-by: coleenp, fbredberg --- src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp | 2 +- src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp | 2 +- src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp | 2 +- src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp | 10 +--------- src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp | 2 +- src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp | 2 +- src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp | 2 +- src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp | 2 +- src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp | 2 +- src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 2 +- src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp | 10 +--------- 11 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 3ab81697280a..5c84669776db 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -389,7 +389,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index 6f31bc284e35..90a61b7e8b63 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -374,7 +374,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index 8668f20e371d..a380c4f316cf 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -433,7 +433,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index a089d5981ca5..c9a537feacb5 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -145,14 +145,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ShouldNotCallThis(); } - // jni_fast_GetField can trap at certain pc's if a GC - // kicks in and the heap gets shrunk before the field access. - /*if (sig == SIGSEGV || sig == SIGBUS) { - address addr = JNI_FastGetField::find_slowcase_pc(pc); - if (addr != (address)-1) { - stub = addr; - } - }*/ } return false; diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 67e0569bf31d..216e6b729909 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -302,7 +302,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 41a4dbea3842..3f158ad9cee4 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -376,7 +376,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if (sig == SIGSEGV || sig == SIGBUS) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 518519937306..859adcd8b4ee 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -405,7 +405,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index 7634ac0fd379..d059046c57fb 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -283,7 +283,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr_slow = JNI_FastGetField::find_slowcase_pc(pc); if (addr_slow != (address)-1) { stub = addr_slow; diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 9276d1d744b0..cbb06d2d07d8 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -349,7 +349,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 25ee449d8b10..261739d8c35f 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -297,7 +297,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // jni_fast_GetField can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { + if (stub == nullptr && ((sig == SIGSEGV) || (sig == SIGBUS))) { address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) { stub = addr; diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index ee9c5e2dfb23..6cad3e9fff95 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -260,14 +260,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ShouldNotCallThis(); } - // jni_fast_GetField can trap at certain pc's if a GC - // kicks in and the heap gets shrunk before the field access. - /*if (sig == SIGSEGV || sig == SIGBUS) { - address addr = JNI_FastGetField::find_slowcase_pc(pc); - if (addr != (address)-1) { - stub = addr; - } - }*/ } return false; // Fatal error From db325dd0382975cd967bd6b817abf6abc5c2a397 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 27 Aug 2026 05:39:10 +0000 Subject: [PATCH 103/223] 8391160: C2 uses a raw base for an oop arraycopy destination Reviewed-by: qamai, chagedorn, shade, kvn --- src/hotspot/share/opto/macroArrayCopy.cpp | 4 ---- .../TestCopyOfBrokenAntiDependency.java | 12 +++++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 678c083f808f..2e549ca05f9a 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -1418,10 +1418,6 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { if (ac->_dest_type != TypeOopPtr::BOTTOM) { adr_type = ac->_dest_type->add_offset(Type::OffsetBot)->is_ptr(); } - if (ac->_src_type != ac->_dest_type) { - adr_type = TypeRawPtr::BOTTOM; - raw_base = true; - } } merge_mem = MergeMemNode::make(mem); transform_later(merge_mem); diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestCopyOfBrokenAntiDependency.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestCopyOfBrokenAntiDependency.java index 508d50723695..6c3c5ab6af3d 100644 --- a/test/hotspot/jtreg/compiler/escapeAnalysis/TestCopyOfBrokenAntiDependency.java +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestCopyOfBrokenAntiDependency.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Red Hat, Inc. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +24,14 @@ /** * @test - * @bug 8238384 - * @summary CTW: C2 compilation fails with "assert(store != load->find_exact_control(load->in(0))) failed: dependence cycle found" - * - * @run main/othervm -XX:-BackgroundCompilation TestCopyOfBrokenAntiDependency - * + * @bug 8238384 8391160 + * @summary Test that Arrays.copyOf with non-escaping allocations and distinct memory slices compiles without assertion failures + * @run main/othervm -Xbatch ${test.main.class} + * @run main/othervm -Xbatch -XX:-ReduceInitialCardMarks -XX:-ReduceBulkZeroing ${test.main.class} */ +package compiler.escapeAnalysis; + import java.util.Arrays; public class TestCopyOfBrokenAntiDependency { From fee14c4e9730242e5937f784eada53825b65884b Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 27 Aug 2026 05:41:24 +0000 Subject: [PATCH 104/223] 8390619: Validate sender SP before to return sender frame in LinuxAMD64CFrame.java Reviewed-by: cjplummer, kevinw --- .../hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index ece221e9ef3d..b9ab97e3cef2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -79,6 +79,12 @@ private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address }; } + // In SysV AMD64, SP should be less than sender SP because return address should be + // pushed onto the stack. + protected boolean isValidFrame(Address senderCFA, Address senderFP, Address senderSP) { + return super.isValidFrame(senderCFA, senderFP) && sp().lessThan(senderSP); + } + @Override public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) { if (linuxDbg().isSignalTrampoline(pc())) { @@ -124,7 +130,7 @@ public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address try { Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP); - return isValidFrame(senderCFA, senderFP) + return isValidFrame(senderCFA, senderFP, senderSP) ? new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback) : null; } catch (DebuggerException e) { From 2a27f21360d9dcf799b4ec5ced5c9e7ed7841435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20B=C3=A1lek?= Date: Thu, 27 Aug 2026 07:13:27 +0000 Subject: [PATCH 105/223] 8391170: JLinkToolProviderTest fails after JDK-8390505 when using configure --enable-linkable-runtime Reviewed-by: sgehwolf, alanb --- test/jdk/tools/jlink/JLinkToolProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jlink/JLinkToolProviderTest.java b/test/jdk/tools/jlink/JLinkToolProviderTest.java index 94959dcc8d80..ba9eab5c9314 100644 --- a/test/jdk/tools/jlink/JLinkToolProviderTest.java +++ b/test/jdk/tools/jlink/JLinkToolProviderTest.java @@ -34,7 +34,7 @@ /* * @test * @modules jdk.jlink - * @run main JLinkToolProviderTest + * @run main/othervm JLinkToolProviderTest */ public class JLinkToolProviderTest { static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") From 3c0d1f5294b2d430c1d9f0f6aedd2f68149f9c19 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 27 Aug 2026 07:47:15 +0000 Subject: [PATCH 106/223] 8387668: javac should warn on use of value classes Reviewed-by: vromero, mcimadamore --- .../com/sun/tools/javac/code/Preview.java | 2 +- .../com/sun/tools/javac/jvm/ClassWriter.java | 9 -- .../tools/javac/patterns/DominationWithPP.out | 2 + .../tools/javac/patterns/T8309054.java | 1 - .../tools/javac/patterns/T8309054.out | 12 +- .../tools/javac/patterns/T8314578.java | 1 - .../tools/javac/patterns/T8314578.out | 6 +- .../tools/javac/patterns/T8332463b.out | 2 + .../tools/javac/preview/PreviewJRTImage.java | 2 + .../LoadableDescriptorsAttrTest2.java | 123 +++++++++++++++--- 10 files changed, 121 insertions(+), 39 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index 3e41ccb5766e..8903088e4b20 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -260,7 +260,7 @@ public Error disabledError(JavaFileObject classfile, int majorVersion) { * @return true iff sym has been declared using a preview language feature */ public boolean declaredUsingPreviewFeature(Symbol sym) { - return false; + return sym.isValueClass(); } public void checkSourceLevel(DiagnosticPosition pos, Feature feature) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index afd3fed8757e..39c0339ac287 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -1002,9 +1002,6 @@ void writeField(VarSymbol v) { Type fldType = v.erasure(types); if (fldType.requiresLoadableDescriptors(v.owner)) { poolWriter.enterLoadableDescriptorsClass(fldType.tsym); - if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { - preview.markUsesPreview(null); - } } int acountIdx = beginAttrs(); int acount = 0; @@ -1035,17 +1032,11 @@ void writeMethod(MethodSymbol m) { for (Type t : mtype.getParameterTypes()) { if (t.requiresLoadableDescriptors(m.owner)) { poolWriter.enterLoadableDescriptorsClass(t.tsym); - if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { - preview.markUsesPreview(null); - } } } Type returnType = mtype.getReturnType(); if (returnType.requiresLoadableDescriptors(m.owner)) { poolWriter.enterLoadableDescriptorsClass(returnType.tsym); - if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { - preview.markUsesPreview(null); - } } int acountIdx = beginAttrs(); int acount = 0; diff --git a/test/langtools/tools/javac/patterns/DominationWithPP.out b/test/langtools/tools/javac/patterns/DominationWithPP.out index 119cc003d071..9a1c17a5cdd3 100644 --- a/test/langtools/tools/javac/patterns/DominationWithPP.out +++ b/test/langtools/tools/javac/patterns/DominationWithPP.out @@ -11,4 +11,6 @@ Domination.java:193:18: compiler.err.pattern.dominated Domination.java:202:18: compiler.err.pattern.dominated Domination.java:211:18: compiler.err.pattern.dominated Domination.java:228:18: compiler.err.pattern.dominated +- compiler.note.preview.filename: Domination.java, DEFAULT +- compiler.note.preview.recompile 13 errors diff --git a/test/langtools/tools/javac/patterns/T8309054.java b/test/langtools/tools/javac/patterns/T8309054.java index 27e9cbe0c1bf..b504624b7ff7 100644 --- a/test/langtools/tools/javac/patterns/T8309054.java +++ b/test/langtools/tools/javac/patterns/T8309054.java @@ -2,7 +2,6 @@ * @test /nodynamiccopyright/ * @bug 8309054 * @summary Parsing of erroneous patterns succeeds - * @enablePreview * @compile/fail/ref=T8309054.out -XDrawDiagnostics --should-stop=at=FLOW T8309054.java */ diff --git a/test/langtools/tools/javac/patterns/T8309054.out b/test/langtools/tools/javac/patterns/T8309054.out index 4397d51ec0be..79c187a8d222 100644 --- a/test/langtools/tools/javac/patterns/T8309054.out +++ b/test/langtools/tools/javac/patterns/T8309054.out @@ -1,7 +1,7 @@ -T8309054.java:12:24: compiler.err.expected2: :, -> -T8309054.java:16:26: compiler.err.expected2: :, -> -T8309054.java:19:35: compiler.err.expected: ')' -T8309054.java:13:13: compiler.err.switch.mixing.case.types -T8309054.java:17:13: compiler.err.switch.mixing.case.types -T8309054.java:21:17: compiler.err.unexpected.type: kindname.variable, kindname.value +T8309054.java:11:24: compiler.err.expected2: :, -> +T8309054.java:15:26: compiler.err.expected2: :, -> +T8309054.java:18:35: compiler.err.expected: ')' +T8309054.java:12:13: compiler.err.switch.mixing.case.types +T8309054.java:16:13: compiler.err.switch.mixing.case.types +T8309054.java:20:17: compiler.err.unexpected.type: kindname.variable, kindname.value 6 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/T8314578.java b/test/langtools/tools/javac/patterns/T8314578.java index 28acaec3482a..11eeb310f9d2 100644 --- a/test/langtools/tools/javac/patterns/T8314578.java +++ b/test/langtools/tools/javac/patterns/T8314578.java @@ -1,7 +1,6 @@ /** * @test /nodynamiccopyright/ * @bug 8314578 - * @enablePreview * @summary Parsing of erroneous patterns succeeds * @compile/fail/ref=T8314578.out -XDrawDiagnostics T8314578.java */ diff --git a/test/langtools/tools/javac/patterns/T8314578.out b/test/langtools/tools/javac/patterns/T8314578.out index 1f09c496f57c..de1b3e7d38eb 100644 --- a/test/langtools/tools/javac/patterns/T8314578.out +++ b/test/langtools/tools/javac/patterns/T8314578.out @@ -1,4 +1,4 @@ -T8314578.java:14:18: compiler.err.flows.through.from.pattern -T8314578.java:15:18: compiler.err.flows.through.to.pattern -T8314578.java:27:18: compiler.err.flows.through.to.pattern +T8314578.java:13:18: compiler.err.flows.through.from.pattern +T8314578.java:14:18: compiler.err.flows.through.to.pattern +T8314578.java:26:18: compiler.err.flows.through.to.pattern 3 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/T8332463b.out b/test/langtools/tools/javac/patterns/T8332463b.out index f912242a6c65..b5fcc5c2e4d1 100644 --- a/test/langtools/tools/javac/patterns/T8332463b.out +++ b/test/langtools/tools/javac/patterns/T8332463b.out @@ -1,2 +1,4 @@ T8332463b.java:36:18: compiler.err.pattern.dominated +- compiler.note.preview.filename: T8332463b.java, DEFAULT +- compiler.note.preview.recompile 1 error diff --git a/test/langtools/tools/javac/preview/PreviewJRTImage.java b/test/langtools/tools/javac/preview/PreviewJRTImage.java index 4e97a7688a99..fae29d0434d5 100644 --- a/test/langtools/tools/javac/preview/PreviewJRTImage.java +++ b/test/langtools/tools/javac/preview/PreviewJRTImage.java @@ -111,6 +111,8 @@ void test() { "Test.java:1:16: compiler.warn.sun.proprietary: sun.misc.Unsafe", "Test.java:5:9: compiler.err.type.found.req: java.lang.Boolean, (compiler.misc.type.req.identity)", "Test.java:7:9: compiler.warn.sun.proprietary: sun.misc.Unsafe", + "- compiler.note.preview.filename: Test.java, DEFAULT", + "- compiler.note.preview.recompile", "1 error", "2 warnings" ); diff --git a/test/langtools/tools/javac/valhalla/value-objects/LoadableDescriptorsAttrTest2.java b/test/langtools/tools/javac/valhalla/value-objects/LoadableDescriptorsAttrTest2.java index e16c064b0695..8908e4ee88e5 100644 --- a/test/langtools/tools/javac/valhalla/value-objects/LoadableDescriptorsAttrTest2.java +++ b/test/langtools/tools/javac/valhalla/value-objects/LoadableDescriptorsAttrTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,9 +41,11 @@ import java.lang.classfile.ClassFile; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import com.sun.tools.javac.util.Assert; +import toolbox.Task.OutputKind; import toolbox.TestRunner; import toolbox.ToolBox; @@ -81,24 +83,53 @@ class Ident { Path classes = base.resolve("classes"); tb.createDirectories(classes); - new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature())) + List log; + List expected; + + expected = List.of( + "Ident.java:2:5: compiler.warn.declared.using.preview: kindname.class, Val", + "Val.java:1:1: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.value.classes)", + "2 warnings" + ); + + log = new toolbox.JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(findJavaFiles(src)) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); + Path classFilePath = classes.resolve("Ident.class"); var classFile = ClassFile.of().parse(classFilePath); Assert.check(classFile.minorVersion() == 65535); Assert.check(classFile.findAttribute(Attributes.loadableDescriptors()).isPresent()); + expected = List.of( + "- compiler.warn.preview.feature.use.classfile: Val.class, 28", + "Ident.java:2:5: compiler.warn.declared.using.preview: kindname.class, Val", + "2 warnings" + ); + // now with the value class in the classpath - new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature()), "-cp", classes.toString()) + log = new toolbox.JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-cp", classes.toString(), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(src.resolve("Ident.java")) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); classFilePath = classes.resolve("Ident.class"); classFile = ClassFile.of().parse(classFilePath); @@ -121,24 +152,53 @@ void m(Val val) {} Path classes = base.resolve("classes"); tb.createDirectories(classes); - new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature())) + List log; + List expected; + + expected = List.of( + "Ident.java:2:12: compiler.warn.declared.using.preview: kindname.class, Val", + "Val.java:1:1: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.value.classes)", + "2 warnings" + ); + + log = new toolbox.JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(findJavaFiles(src)) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); + Path classFilePath = classes.resolve("Ident.class"); var classFile = ClassFile.of().parse(classFilePath); Assert.check(classFile.minorVersion() == 65535); Assert.check(classFile.findAttribute(Attributes.loadableDescriptors()).isPresent()); + expected = List.of( + "- compiler.warn.preview.feature.use.classfile: Val.class, 28", + "Ident.java:2:12: compiler.warn.declared.using.preview: kindname.class, Val", + "2 warnings" + ); + // now with the value class in the classpath - new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature()), "-cp", classes.toString()) + log = new toolbox.JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-cp", classes.toString(), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(src.resolve("Ident.java")) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); classFilePath = classes.resolve("Ident.class"); classFile = ClassFile.of().parse(classFilePath); @@ -164,25 +224,52 @@ Val m() { Path classes = base.resolve("classes"); tb.createDirectories(classes); - new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature())) + List log; + List expected; + + expected = List.of( + "Ident.java:2:5: compiler.warn.declared.using.preview: kindname.class, Val", + "Val.java:1:1: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.value.classes)", + "2 warnings" + ); + + log = new toolbox.JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(findJavaFiles(src)) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); + Path classFilePath = classes.resolve("Ident.class"); var classFile = ClassFile.of().parse(classFilePath); Assert.check(classFile.minorVersion() == 65535); Assert.check(classFile.findAttribute(Attributes.loadableDescriptors()).isPresent()); + expected = List.of( + "Ident.java:2:5: compiler.warn.declared.using.preview: kindname.class, Val", + "Val.java:1:1: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.value.classes)", + "2 warnings" + ); // now with the value class in the classpath new toolbox.JavacTask(tb) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature()), "-cp", classes.toString()) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), "-cp", classes.toString(), + "-XDrawDiagnostics", + "-Xlint:preview") .outdir(classes) .files(src.resolve("Ident.java")) .run() - .writeAll(); + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + tb.checkEqual(log, expected); classFilePath = classes.resolve("Ident.class"); classFile = ClassFile.of().parse(classFilePath); From ca8a47cc0b709aea35b2e7283b8d82a94b02fca7 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 27 Aug 2026 08:04:13 +0000 Subject: [PATCH 107/223] 8388858: C2: Add UseLoopLimitCheckPredicate and UseParsePredicates flags Reviewed-by: thartmann, mchevalier --- src/hotspot/share/opto/c2_globals.hpp | 8 + src/hotspot/share/opto/graphKit.cpp | 13 +- src/hotspot/share/opto/loopnode.cpp | 9 +- src/hotspot/share/opto/predicates.hpp | 38 +++-- src/hotspot/share/runtime/arguments.cpp | 31 ++++ .../compiler/lib/ir_framework/IRNode.java | 5 + .../TestParallelIvInIntCountedLoop.java | 6 +- .../TestDisabledLoopPredicates.java | 95 ------------ .../TestDisabledParsePredicates.java | 146 ++++++++++++++++++ 9 files changed, 242 insertions(+), 109 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/predicates/TestDisabledLoopPredicates.java create mode 100644 test/hotspot/jtreg/compiler/predicates/TestDisabledParsePredicates.java diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 33799f25d4f4..6a3ef6f2dc90 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -245,6 +245,9 @@ product(bool, UseCountedLoopSafepoints, false, \ "Force counted loops to keep a safepoint") \ \ + product(bool, UseParsePredicates, true, DIAGNOSTIC, \ + "Use Parse Predicates for speculative optimizations.") \ + \ product(bool, UseLoopPredicate, true, \ "Move checks with uncommon trap out of loops.") \ \ @@ -257,6 +260,11 @@ develop(bool, TraceSplitIf, false, \ "Trace Split-If optimization") \ \ + product(bool, UseLoopLimitCheckPredicate, true, DIAGNOSTIC, \ + "Use Loop Limit Check Predicate to speculatively transform " \ + "loops to counted loops where overflow is uncertain at " \ + "compile time.") \ + \ develop(bool, TraceLoopLimitCheck, false, \ "Trace generation of loop limits checks") \ \ diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 81b9fa501665..469b1016f3d6 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4785,22 +4785,31 @@ void GraphKit::add_parse_predicate(Deoptimization::DeoptReason reason, const int // Add Parse Predicates which serve as placeholders to create new Runtime Predicates above them. All // Runtime Predicates inside a Runtime Predicate block share the same uncommon trap as the Parse Predicate. void GraphKit::add_parse_predicates(int nargs) { + if (!UseParsePredicates) { + return; + } + if (ShortRunningLongLoop) { // Will narrow the limit down with a cast node. Predicates added later may depend on the cast so should be last when // walking up from the loop. add_parse_predicate(Deoptimization::Reason_short_running_long_loop, nargs); } + if (UseLoopPredicate) { add_parse_predicate(Deoptimization::Reason_predicate, nargs); if (UseProfiledLoopPredicate) { add_parse_predicate(Deoptimization::Reason_profile_predicate, nargs); } } + if (UseAutoVectorizationPredicate) { add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, nargs); } - // Loop Limit Check Predicate should be near the loop. - add_parse_predicate(Deoptimization::Reason_loop_limit_check, nargs); + + if (UseLoopLimitCheckPredicate) { + // Loop Limit Check Predicate should be near the loop. + add_parse_predicate(Deoptimization::Reason_loop_limit_check, nargs); + } } void GraphKit::sync_kit(IdealKit& ideal) { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index bf461fc17a8a..2a5f61820202 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -706,9 +706,14 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, const Node* he } void PhaseIdealLoop::add_parse_predicates(IdealLoopTree* outer_ilt, LoopNode* inner_head, SafePointNode* cloned_sfpt) { + if (!UseParsePredicates) { + return; + } + if (ShortRunningLongLoop) { add_parse_predicate(Deoptimization::Reason_short_running_long_loop, inner_head, outer_ilt, cloned_sfpt); } + if (UseLoopPredicate) { add_parse_predicate(Deoptimization::Reason_predicate, inner_head, outer_ilt, cloned_sfpt); if (UseProfiledLoopPredicate) { @@ -720,7 +725,9 @@ void PhaseIdealLoop::add_parse_predicates(IdealLoopTree* outer_ilt, LoopNode* in add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); } - add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); + if (UseLoopLimitCheckPredicate) { + add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); + } } // If the loop has the shape of a counted loop but with a long diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index cd0832cc062c..32c59edda315 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -816,22 +816,40 @@ class PredicateIterator : public StackObj { // Returns the entry to the earliest predicate. Node* for_each(PredicateVisitor& predicate_visitor) const { Node* current_node = _start_node; - PredicateBlockIterator loop_limit_check_predicate_iterator(current_node, Deoptimization::Reason_loop_limit_check); - current_node = loop_limit_check_predicate_iterator.for_each(predicate_visitor); + if (!UseParsePredicates) { + // We cannot do nothing when UseParsePredicates is not set: We could still have Assertion Predicates from Range + // Check Elimination even without Parse Predicates. We have one "generic" block, but we use + // Reason_loop_limit_check (could also use another predicate related reason) to not confuse the iteration logic + // with non-predicate deoptimization reasons. + return apply_for(predicate_visitor, current_node, Deoptimization::Reason_loop_limit_check); + } + + if (UseLoopLimitCheckPredicate) { + current_node = apply_for(predicate_visitor, current_node, Deoptimization::Reason_loop_limit_check); + } + if (UseAutoVectorizationPredicate) { - PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check); - current_node = auto_vectorization_check_iterator.for_each(predicate_visitor); + current_node = apply_for(predicate_visitor, current_node, Deoptimization::Reason_auto_vectorization_check); } + if (UseLoopPredicate) { if (UseProfiledLoopPredicate) { - PredicateBlockIterator profiled_loop_predicate_iterator(current_node, Deoptimization::Reason_profile_predicate); - current_node = profiled_loop_predicate_iterator.for_each(predicate_visitor); + current_node = apply_for(predicate_visitor, current_node, Deoptimization::Reason_profile_predicate); } - PredicateBlockIterator loop_predicate_iterator(current_node, Deoptimization::Reason_predicate); - current_node = loop_predicate_iterator.for_each(predicate_visitor); + current_node = apply_for(predicate_visitor, current_node, Deoptimization::Reason_predicate); } - PredicateBlockIterator short_running_loop_predicate_iterator(current_node, Deoptimization::Reason_short_running_long_loop); - return short_running_loop_predicate_iterator.for_each(predicate_visitor); + + if (ShortRunningLongLoop) { + current_node = apply_for(predicate_visitor, current_node, Deoptimization::Reason_short_running_long_loop); + } + return current_node; + } + + private: + [[nodiscard]] static Node* apply_for(PredicateVisitor& predicate_visitor, Node* current_node, + Deoptimization::DeoptReason reason) { + PredicateBlockIterator predicate_block_iterator(current_node, reason); + return predicate_block_iterator.for_each(predicate_visitor); } }; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 136316fcffdf..cff14087d75c 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3606,6 +3606,37 @@ jint Arguments::apply_ergo() { warning("Disabling UseProfiledLoopPredicate since UseLoopPredicate is turned off."); FLAG_SET_ERGO(UseProfiledLoopPredicate, false); } + + bool any_parse_predicate_flag_enabled = UseLoopLimitCheckPredicate || + UseAutoVectorizationPredicate || + UseLoopPredicate || + UseProfiledLoopPredicate || + ShortRunningLongLoop; + + if (!UseParsePredicates && any_parse_predicate_flag_enabled) { + // Disable any Parse Predicate enabling flag when UseParsePredicates is not set. + FLAG_SET_ERGO(UseLoopLimitCheckPredicate, false); + FLAG_SET_ERGO(UseLoopPredicate, false); + FLAG_SET_ERGO(UseProfiledLoopPredicate, false); + FLAG_SET_ERGO(UseAutoVectorizationPredicate, false); + FLAG_SET_ERGO(ShortRunningLongLoop, false); + + if ((!FLAG_IS_DEFAULT(UseLoopLimitCheckPredicate) && UseLoopLimitCheckPredicate) || + (!FLAG_IS_DEFAULT(UseAutoVectorizationPredicate) && UseAutoVectorizationPredicate) || + (!FLAG_IS_DEFAULT(UseLoopPredicate) && UseLoopPredicate) || + (!FLAG_IS_DEFAULT(UseProfiledLoopPredicate) && UseProfiledLoopPredicate) || + (!FLAG_IS_DEFAULT(ShortRunningLongLoop) && ShortRunningLongLoop)) { + warning("Disabling UseParsePredicates disables all Parse Predicate enabling flags: UseLoopLimitCheckPredicate," + " UseLoopPredicate, UseProfiledLoopPredicate, UseAutoVectorizationPredicate, and ShortRunningLongLoop"); + } + + } + + if (UseParsePredicates && !any_parse_predicate_flag_enabled) { + warning("Disabling UseParsePredicates because all Parse Predicate flags are disabled: UseLoopLimitCheckPredicate," + " UseLoopPredicate, UseProfiledLoopPredicate, UseAutoVectorizationPredicate, and ShortRunningLongLoop"); + FLAG_SET_ERGO(UseParsePredicates, false); + } #endif // COMPILER2 if (log_is_enabled(Info, perf, class, link)) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index a59331a9239d..510c9f7ef369 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1885,6 +1885,11 @@ public static void anyLoadOfNodes(String irNodePlaceholder, String fieldHolder) parsePredicateNodes(AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "Auto_Vectorization_Check"); } + public static final String SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE = PREFIX + "SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE" + POSTFIX; + static { + parsePredicateNodes(SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "Short_Running_Long_Loop"); + } + public static final String PREDICATE_TRAP = PREFIX + "PREDICATE_TRAP" + POSTFIX; static { trapNodes(PREDICATE_TRAP, "predicate"); diff --git a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java index f8abb716e425..ee75614be735 100644 --- a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java +++ b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +50,10 @@ public static void main(String[] args) { TestFramework.runWithFlags( "-XX:+IgnoreUnrecognizedVMOptions", // StressLongCountedLoop is only available in debug builds "-XX:StressLongCountedLoop=0", // Don't convert int counted loops to long ones - "-XX:PerMethodTrapLimit=100" // allow slow-path loop limit checks + // Allow slow-path loop limit checks + "-XX:PerMethodTrapLimit=100", + "-XX:+UseLoopLimitCheckPredicate", + "-XX:+UseParsePredicates" ); } diff --git a/test/hotspot/jtreg/compiler/predicates/TestDisabledLoopPredicates.java b/test/hotspot/jtreg/compiler/predicates/TestDisabledLoopPredicates.java deleted file mode 100644 index c74e22cb68a0..000000000000 --- a/test/hotspot/jtreg/compiler/predicates/TestDisabledLoopPredicates.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package compiler.predicates; - -import compiler.lib.ir_framework.*; -import jdk.test.lib.Asserts; - -/* - * @test - * @bug 8347449 - * @summary Test that profiled loop predicates are turned off if loop predicates are turned off - * @library /test/lib / - * @run driver compiler.predicates.TestDisabledLoopPredicates - */ - -public class TestDisabledLoopPredicates { - static final int SIZE = 100; - static final int MIN = 3; - - public static void main(String[] args) { - TestFramework.runWithFlags("-XX:+UseLoopPredicate", - "-XX:+UseProfiledLoopPredicate"); - TestFramework.runWithFlags("-XX:-UseLoopPredicate"); - TestFramework.runWithFlags("-XX:-UseProfiledLoopPredicate"); - } - - @Run(test = "test") - private static void check() { - int res = test(true); - Asserts.assertEQ(res, ((SIZE - 1) * SIZE - MIN * (MIN + 1)) / 2); - } - - @DontInline - private static void blackhole(int i) { - } - - @DontInline - private static int[] getArr() { - int[] arr = new int[SIZE]; - for (int i = 0; i < SIZE; i++) { - arr[i] = i; - } - - return arr; - } - - @Test - @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", - IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1" }, - applyIfAnd = { "UseLoopPredicate", "true", - "UseProfiledLoopPredicate", "true" }) - @IR(failOn = { IRNode.LOOP_PARSE_PREDICATE, - IRNode.PROFILED_LOOP_PARSE_PREDICATE }, - applyIf = { "UseLoopPredicate", "false" }) - @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1" }, - failOn = { IRNode.PROFILED_LOOP_PARSE_PREDICATE }, - applyIfAnd = { "UseLoopPredicate", "true", - "UseProfiledLoopPredicate", "false" }) - public static int test(boolean cond) { - int[] arr = getArr(); - int sum = 0; - for (int i = 0; i < arr.length; i++) { - if (cond) { - if (arr[i] > MIN) { - sum += arr[i]; - } - } - blackhole(arr[i]); - } - - return sum; - } -} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/predicates/TestDisabledParsePredicates.java b/test/hotspot/jtreg/compiler/predicates/TestDisabledParsePredicates.java new file mode 100644 index 000000000000..abd484c22b8d --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/TestDisabledParsePredicates.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.predicates; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8347449 8388858 + * @summary Test that profiled loop predicates are turned off if loop predicates are turned off + * @library /test/lib / + * @run driver ${test.main.class} + */ + +public class TestDisabledParsePredicates { + static final int SIZE = 100; + static final int MIN = 3; + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UseLoopPredicate", + "-XX:+UseProfiledLoopPredicate"); + TestFramework.runWithFlags("-XX:-UseLoopPredicate"); + TestFramework.runWithFlags("-XX:-UseProfiledLoopPredicate"); + TestFramework.runWithFlags("-XX:-UseParsePredicates"); + TestFramework.runWithFlags("-XX:-UseLoopLimitCheckPredicate"); + TestFramework.runWithFlags("-XX:-UseAutoVectorizationPredicate"); + TestFramework.runWithFlags("-XX:-ShortRunningLongLoop"); + } + + @Run(test = "test") + private static void check() { + int res = test(true); + Asserts.assertEQ(res, ((SIZE - 1) * SIZE - MIN * (MIN + 1)) / 2); + } + + @DontInline + private static void blackhole(int i) { + } + + @DontInline + private static int[] getArr() { + int[] arr = new int[SIZE]; + for (int i = 0; i < SIZE; i++) { + arr[i] = i; + } + + return arr; + } + + @Test + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1", + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "1"}, + applyIfAnd = { "UseLoopPredicate", "true", + "UseProfiledLoopPredicate", "true", + "UseLoopLimitCheckPredicate", "true", + "UseAutoVectorizationPredicate", "true", + "ShortRunningLongLoop", "true"}) + @IR(failOn = { IRNode.LOOP_PARSE_PREDICATE, + IRNode.PROFILED_LOOP_PARSE_PREDICATE }, + counts = { IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1", + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "1"}, + applyIfAnd = { "UseLoopPredicate", "false", + "UseParsePredicates", "true", + "UseLoopLimitCheckPredicate", "true", + "UseAutoVectorizationPredicate", "true", + "ShortRunningLongLoop", "true"}) + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1", + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "1"}, + failOn = { IRNode.PROFILED_LOOP_PARSE_PREDICATE }, + applyIfAnd = { "UseLoopPredicate", "true", + "UseLoopLimitCheckPredicate", "true", + "UseAutoVectorizationPredicate", "true", + "ShortRunningLongLoop", "true", + "UseProfiledLoopPredicate", "false" }) + @IR(failOn = { IRNode.LOOP_PARSE_PREDICATE, + IRNode.PROFILED_LOOP_PARSE_PREDICATE, + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE}, + applyIf = { "UseParsePredicates", "false"}) + + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1", + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "1"}, + failOn = { IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE }, + applyIfAnd = { "UseLoopLimitCheckPredicate", "false", + "UseParsePredicates", "true" }) + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE, "1"}, + failOn = { IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE }, + applyIfAnd = { "UseAutoVectorizationPredicate", "false", + "UseParsePredicates", "true" }) + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1"}, + failOn = { IRNode.SHORT_RUNNING_LONG_LOOP_PARSE_PREDICATE }, + applyIfAnd = { "ShortRunningLongLoop", "false", + "UseParsePredicates", "true" }) + public static int test(boolean cond) { + int[] arr = getArr(); + int sum = 0; + for (int i = 0; i < arr.length; i++) { + if (cond) { + if (arr[i] > MIN) { + sum += arr[i]; + } + } + blackhole(arr[i]); + } + + return sum; + } +} From b747e1abbcb02af97e09543009e9f83e95096e41 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Thu, 27 Aug 2026 09:17:42 +0000 Subject: [PATCH 108/223] 8390947: C2: GTest test_typejavaptr.cpp intermittently fails with assert(ptr2 == TypePtr::Constant || ptr2 == TypePtr::NotNull || ptr2 == TypePtr::BotPTR) failed: unexpected ptr: 0 Reviewed-by: dlong, shade --- test/hotspot/gtest/opto/test_typejavaptr.cpp | 27 ++++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/test/hotspot/gtest/opto/test_typejavaptr.cpp b/test/hotspot/gtest/opto/test_typejavaptr.cpp index 89fbebcf1e41..6bf42c251fd3 100644 --- a/test/hotspot/gtest/opto/test_typejavaptr.cpp +++ b/test/hotspot/gtest/opto/test_typejavaptr.cpp @@ -51,6 +51,17 @@ class TypeAryKlassPtrMirror; // tests. // - Mirror instances are created at compile time, ensuring the absence of unexpected behaviors. +// For GCC, UBSAN breaks the constexpr evaluation, which results in compilation failure. +// For MSVC, the constexpr evaluation mechanism on GHA seems to have a smaller computing step +// limit, which results in it failing to compute _2d_samples, which is a constexpr variable. +// Our workaround to those compiler issues is to compute the variables at runtime instead. The +// downside is that we do not benefit from the lack-of-UB guarantee of constexpr evaluation. +#ifdef __clang__ +#define MAYBE_CONSTEXPR constexpr +#else // __clang__ +#define MAYBE_CONSTEXPR const +#endif // __clang__ + class InterfaceSet { public: bool _i0; @@ -987,7 +998,7 @@ constexpr auto TypeAryPtrMirror::generate_1d_elem_samples() { return res; } -constexpr std::array, TypeAryPtrMirror::_1d_elem_samples_size> TypeAryPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); +MAYBE_CONSTEXPR std::array, TypeAryPtrMirror::_1d_elem_samples_size> TypeAryPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); template constexpr void TypeAryPtrMirror::fill_samples_helper(R& res, size_t& sample_idx, TypePtr::PTR ptr, InstanceMirror const_oop, const AryElemType* elem, @@ -1128,7 +1139,7 @@ constexpr auto TypeAryPtrMirror::generate_1d_samples() { return res; } -constexpr std::array TypeAryPtrMirror::_1d_samples = generate_1d_samples(); +MAYBE_CONSTEXPR std::array TypeAryPtrMirror::_1d_samples = generate_1d_samples(); constexpr auto TypeAryPtrMirror::generate_2d_elem_samples() { std::array, _2d_elem_samples_size> res; @@ -1152,7 +1163,7 @@ constexpr auto TypeAryPtrMirror::generate_2d_elem_samples() { return res; } -constexpr std::array, TypeAryPtrMirror::_2d_elem_samples_size> TypeAryPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); +MAYBE_CONSTEXPR std::array, TypeAryPtrMirror::_2d_elem_samples_size> TypeAryPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); constexpr auto TypeAryPtrMirror::generate_2d_samples() { std::array res; @@ -1194,7 +1205,7 @@ constexpr auto TypeAryPtrMirror::generate_2d_samples() { return res; } -constexpr std::array TypeAryPtrMirror::_2d_samples = generate_2d_samples(); +MAYBE_CONSTEXPR std::array TypeAryPtrMirror::_2d_samples = generate_2d_samples(); class TypeKlassPtrMirror : public TypePtrMirror { private: @@ -1580,7 +1591,7 @@ constexpr auto TypeAryKlassPtrMirror::generate_1d_elem_samples() { return res; } -constexpr std::array, TypeAryKlassPtrMirror::_1d_elem_samples_size> TypeAryKlassPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); +MAYBE_CONSTEXPR std::array, TypeAryKlassPtrMirror::_1d_elem_samples_size> TypeAryKlassPtrMirror::_1d_elem_samples = generate_1d_elem_samples(); constexpr auto TypeAryKlassPtrMirror::generate_1d_samples() { std::array res; @@ -1628,7 +1639,7 @@ constexpr auto TypeAryKlassPtrMirror::generate_1d_samples() { return res; } -constexpr std::array TypeAryKlassPtrMirror::_1d_samples = generate_1d_samples(); +MAYBE_CONSTEXPR std::array TypeAryKlassPtrMirror::_1d_samples = generate_1d_samples(); constexpr auto TypeAryKlassPtrMirror::generate_2d_elem_samples() { std::array, _2d_elem_samples_size> res; @@ -1646,7 +1657,7 @@ constexpr auto TypeAryKlassPtrMirror::generate_2d_elem_samples() { return res; } -constexpr std::array, TypeAryKlassPtrMirror::_2d_elem_samples_size> TypeAryKlassPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); +MAYBE_CONSTEXPR std::array, TypeAryKlassPtrMirror::_2d_elem_samples_size> TypeAryKlassPtrMirror::_2d_elem_samples = generate_2d_elem_samples(); constexpr auto TypeAryKlassPtrMirror::generate_2d_samples() { std::array res; @@ -1679,7 +1690,7 @@ constexpr auto TypeAryKlassPtrMirror::generate_2d_samples() { return res; } -constexpr std::array TypeAryKlassPtrMirror::_2d_samples = generate_2d_samples(); +MAYBE_CONSTEXPR std::array TypeAryKlassPtrMirror::_2d_samples = generate_2d_samples(); // OopPtrMirror is the mirror of oop class OopPtrMirror { From 7e552b4da2f8fec3ff08d63543802132bc87b592 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Thu, 27 Aug 2026 09:18:45 +0000 Subject: [PATCH 109/223] 8390617: [REDO] C2: Fix the memory around some intrinsics nodes Reviewed-by: vlivanov, thartmann --- src/hotspot/share/opto/graphKit.cpp | 91 +++++--- src/hotspot/share/opto/graphKit.hpp | 3 +- src/hotspot/share/opto/intrinsicnode.cpp | 2 - src/hotspot/share/opto/intrinsicnode.hpp | 200 +++++++++++------- src/hotspot/share/opto/library_call.cpp | 18 +- .../intrinsics/string/TestAntiDependency.java | 131 ++++++++++++ 6 files changed, 334 insertions(+), 111 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/string/TestAntiDependency.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 469b1016f3d6..eb81eb18ba8f 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -46,14 +46,17 @@ #include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" +#include "opto/memnode.hpp" #include "opto/multnode.hpp" #include "opto/narrowptrnode.hpp" #include "opto/opaquenode.hpp" +#include "opto/opcodes.hpp" #include "opto/parse.hpp" #include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subtypenode.hpp" +#include "opto/type.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" @@ -4880,51 +4883,81 @@ void GraphKit::store_String_coder(Node* str, Node* value) { value, TypeInt::BYTE, T_BYTE, IN_HEAP | MO_UNORDERED); } -// Capture src and dst memory state with a MergeMemNode -Node* GraphKit::capture_memory(const TypePtr* src_type, const TypePtr* dst_type) { +// If input and output memory types differ, capture the whole memory to preserve +// the dependency between preceding and subsequent loads/stores. +// For example, the following program: +// StoreB +// compress_string +// LoadB +// has this memory graph (use->def): +// LoadB -> compress_string -> CharMem +// ... -> StoreB -> ByteMem +// The intrinsic hides the dependency between LoadB and StoreB, causing +// the load to read from memory not containing the result of the StoreB. +// The correct memory graph should look like this: +// LoadB -> compress_string -> MergeMem -> StoreB +Node* GraphKit::capture_memory(const TypePtr*& combined_type, const TypePtr* src_type, const TypePtr* dst_type) { if (src_type == dst_type) { // Types are equal, we don't need a MergeMemNode + combined_type = src_type; return memory(src_type); } - MergeMemNode* merge = MergeMemNode::make(map()->memory()); - record_for_igvn(merge); // fold it up later, if possible - int src_idx = C->get_alias_index(src_type); - int dst_idx = C->get_alias_index(dst_type); - merge->set_memory_at(src_idx, memory(src_idx)); - merge->set_memory_at(dst_idx, memory(dst_idx)); - return merge; + Node* mem = reset_memory(); + set_all_memory(mem); + combined_type = TypePtr::BOTTOM; + return mem; +} + +// If dst_type and src_type are different, str may have an anti-dependency with another node +// consuming src_type. +// For example: +// compress_string +// StoreC +// has this memory graph (use->def): +// compress_string -> MergeMem -> CharMem +// StoreC +// The scheduler needs to ensure that compress_string is not executed after StoreC, or it will read +// the wrong memory. For normal loads, the scheduler computes its anti-dependencies to ensure the +// memory it reads from is not killed. Since we do not compute anti-dependencies for +// StrCompressedCopyNode, manually insert a MemBar so the anti-dependency becomes use-def +// dependency: +// StoreC -> MemBar -> MergeMem -> compress_string -> MergeMem -> CharMem +// --------------------------------> +void GraphKit::memory_effect(Node* res_mem, const TypePtr* src_type, const TypePtr* dst_type) { + set_memory(res_mem, dst_type); + if (src_type != dst_type) { + Node* all_mem = reset_memory(); + set_all_memory(all_mem); + Node* membar = new MemBarCPUOrderNode(C, C->get_alias_index(src_type), nullptr); + membar->init_req(TypeFunc::Control, control()); + membar->init_req(TypeFunc::Memory, all_mem); + membar = _gvn.transform(membar); + set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control))); + set_memory(_gvn.transform(new ProjNode(membar, TypeFunc::Memory)), src_type); + } } Node* GraphKit::compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count) { assert(Matcher::match_rule_supported(Op_StrCompressedCopy), "Intrinsic not supported"); assert(src_type == TypeAryPtr::BYTES || src_type == TypeAryPtr::CHARS, "invalid source type"); - // If input and output memory types differ, capture both states to preserve - // the dependency between preceding and subsequent loads/stores. - // For example, the following program: - // StoreB - // compress_string - // LoadB - // has this memory graph (use->def): - // LoadB -> compress_string -> CharMem - // ... -> StoreB -> ByteMem - // The intrinsic hides the dependency between LoadB and StoreB, causing - // the load to read from memory not containing the result of the StoreB. - // The correct memory graph should look like this: - // LoadB -> compress_string -> MergeMem(CharMem, StoreB(ByteMem)) - Node* mem = capture_memory(src_type, TypeAryPtr::BYTES); - StrCompressedCopyNode* str = new StrCompressedCopyNode(control(), mem, src, dst, count); + const TypePtr* dst_type = TypeAryPtr::BYTES; + const TypePtr* adr_type; + Node* mem = capture_memory(adr_type, src_type, dst_type); + StrCompressedCopyNode* str = new StrCompressedCopyNode(control(), mem, adr_type, src, dst, count); Node* res_mem = _gvn.transform(new SCMemProjNode(_gvn.transform(str))); - set_memory(res_mem, TypeAryPtr::BYTES); + memory_effect(res_mem, src_type, dst_type); return str; } void GraphKit::inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count) { assert(Matcher::match_rule_supported(Op_StrInflatedCopy), "Intrinsic not supported"); assert(dst_type == TypeAryPtr::BYTES || dst_type == TypeAryPtr::CHARS, "invalid dest type"); - // Capture src and dst memory (see comment in 'compress_string'). - Node* mem = capture_memory(TypeAryPtr::BYTES, dst_type); - StrInflatedCopyNode* str = new StrInflatedCopyNode(control(), mem, src, dst, count); - set_memory(_gvn.transform(str), dst_type); + const TypePtr* src_type = TypeAryPtr::BYTES; + const TypePtr* adr_type; + Node* mem = capture_memory(adr_type, src_type, dst_type); + StrInflatedCopyNode* str = new StrInflatedCopyNode(control(), mem, adr_type, src, dst, count); + Node* res_mem = _gvn.transform(str); + memory_effect(res_mem, src_type, dst_type); } void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* count) { diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 59a95baa5e76..1c109cb56757 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -886,7 +886,8 @@ class GraphKit : public Phase { Node* load_String_coder(Node* str, bool set_ctrl); void store_String_value(Node* str, Node* value); void store_String_coder(Node* str, Node* value); - Node* capture_memory(const TypePtr* src_type, const TypePtr* dst_type); + Node* capture_memory(const TypePtr*& combined_type, const TypePtr* src_type, const TypePtr* dst_type); + void memory_effect(Node* res_mem, const TypePtr* src_type, const TypePtr* dst_type); Node* compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count); void inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count); void inflate_string_slow(Node* src, Node* dst, Node* start, Node* count); diff --git a/src/hotspot/share/opto/intrinsicnode.cpp b/src/hotspot/share/opto/intrinsicnode.cpp index d3e62dacfe80..887681233f16 100644 --- a/src/hotspot/share/opto/intrinsicnode.cpp +++ b/src/hotspot/share/opto/intrinsicnode.cpp @@ -63,8 +63,6 @@ const Type* StrIntrinsicNode::Value(PhaseGVN* phase) const { return bottom_type(); } -uint StrIntrinsicNode::size_of() const { return sizeof(*this); } - //============================================================================= //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out diff --git a/src/hotspot/share/opto/intrinsicnode.hpp b/src/hotspot/share/opto/intrinsicnode.hpp index d81e7bed7e96..1fe61cfb1785 100644 --- a/src/hotspot/share/opto/intrinsicnode.hpp +++ b/src/hotspot/share/opto/intrinsicnode.hpp @@ -48,7 +48,7 @@ class PartialSubtypeCheckNode : public Node { //------------------------------StrIntrinsic------------------------------- // Base class for Ideal nodes used in String intrinsic code. -class StrIntrinsicNode: public Node { +class StrIntrinsicNode : public Node { public: // Possible encodings of the parameters passed to the string intrinsic. // 'L' stands for Latin1 and 'U' stands for UTF16. For example, 'LU' means that @@ -59,7 +59,11 @@ class StrIntrinsicNode: public Node { protected: // Encoding of strings. Used to select the right version of the intrinsic. const ArgEncoding _encoding; - virtual uint size_of() const; + virtual uint size_of() const override { return sizeof(StrIntrinsicNode); } + virtual uint hash() const override { return Node::hash() + _encoding; } + virtual bool cmp(const Node& n) const override { + return Node::cmp(n) && _encoding == static_cast(n)._encoding; + } public: StrIntrinsicNode(Node* control, Node* char_array_mem, @@ -77,141 +81,189 @@ class StrIntrinsicNode: public Node { Node(control, char_array_mem, s1, s2), _encoding(encoding) { } - virtual const TypePtr* adr_type() const { return TypeAryPtr::BYTES; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; + virtual const TypePtr* adr_type() const override = 0; + virtual uint match_edge(uint idx) const override; + virtual uint ideal_reg() const override { return Op_RegI; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + virtual const Type* Value(PhaseGVN* phase) const override; ArgEncoding encoding() const { return _encoding; } private: - virtual bool depends_only_on_test_impl() const { return false; } + virtual bool depends_only_on_test_impl() const override { return false; } }; //------------------------------StrComp------------------------------------- -class StrCompNode: public StrIntrinsicNode { +class StrCompNode final : public StrIntrinsicNode { public: StrCompNode(Node* control, Node* char_array_mem, Node* s1, Node* c1, Node* s2, Node* c2, ArgEncoding encoding): StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2, encoding) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual const TypePtr* adr_type() const override { return TypeAryPtr::BYTES; } }; //------------------------------StrEquals------------------------------------- -class StrEqualsNode: public StrIntrinsicNode { +class StrEqualsNode final : public StrIntrinsicNode { public: StrEqualsNode(Node* control, Node* char_array_mem, Node* s1, Node* s2, Node* c, ArgEncoding encoding): StrIntrinsicNode(control, char_array_mem, s1, s2, c, encoding) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::BOOL; } + virtual const TypePtr* adr_type() const override { return TypeAryPtr::BYTES; } }; //------------------------------StrIndexOf------------------------------------- -class StrIndexOfNode: public StrIntrinsicNode { +class StrIndexOfNode final : public StrIntrinsicNode { public: StrIndexOfNode(Node* control, Node* char_array_mem, Node* s1, Node* c1, Node* s2, Node* c2, ArgEncoding encoding): StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2, encoding) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual const TypePtr* adr_type() const override { return TypeAryPtr::BYTES; } }; //------------------------------StrIndexOfChar------------------------------------- -class StrIndexOfCharNode: public StrIntrinsicNode { +class StrIndexOfCharNode final : public StrIntrinsicNode { public: StrIndexOfCharNode(Node* control, Node* char_array_mem, Node* s1, Node* c1, Node* c, ArgEncoding encoding): StrIntrinsicNode(control, char_array_mem, s1, c1, c, encoding) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual const TypePtr* adr_type() const override { return TypeAryPtr::BYTES; } }; //--------------------------StrCompressedCopy------------------------------- -class StrCompressedCopyNode: public StrIntrinsicNode { - public: - StrCompressedCopyNode(Node* control, Node* arymem, +class StrCompressedCopyNode final : public StrIntrinsicNode { +private: + const TypePtr* const _adr_type; + +public: + StrCompressedCopyNode(Node* control, Node* arymem, const TypePtr* adr_type, Node* s1, Node* s2, Node* c): - StrIntrinsicNode(control, arymem, s1, s2, c, none) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + StrIntrinsicNode(control, arymem, s1, s2, c, none), _adr_type(adr_type) {}; + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + +private: + virtual uint size_of() const override { return sizeof(StrCompressedCopyNode); } + virtual uint hash() const override { return StrIntrinsicNode::hash() + (uint)(uintptr_t) _adr_type; } + virtual bool cmp(const Node& n) const override { + return StrIntrinsicNode::cmp(n) && _adr_type == static_cast(n)._adr_type; + } + virtual const TypePtr* adr_type() const override { return _adr_type; } }; //--------------------------StrInflatedCopy--------------------------------- -class StrInflatedCopyNode: public StrIntrinsicNode { - public: - StrInflatedCopyNode(Node* control, Node* arymem, +class StrInflatedCopyNode final : public StrIntrinsicNode { +private: + const TypePtr* const _adr_type; + +public: + StrInflatedCopyNode(Node* control, Node* arymem, const TypePtr* adr_type, Node* s1, Node* s2, Node* c): - StrIntrinsicNode(control, arymem, s1, s2, c, none) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return Type::MEMORY; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + StrIntrinsicNode(control, arymem, s1, s2, c, none), _adr_type(adr_type) {}; + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return Type::MEMORY; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + +private: + virtual uint size_of() const override { return sizeof(StrInflatedCopyNode); } + virtual uint hash() const override { return StrIntrinsicNode::hash() + (uint)(uintptr_t) _adr_type; } + virtual bool cmp(const Node& n) const override { + return StrIntrinsicNode::cmp(n) && _adr_type == static_cast(n)._adr_type; + } + virtual const TypePtr* adr_type() const override { return _adr_type; } }; //------------------------------AryEq--------------------------------------- -class AryEqNode: public StrIntrinsicNode { - public: - AryEqNode(Node* control, Node* char_array_mem, +class AryEqNode final : public StrIntrinsicNode { +private: + const TypeAryPtr* const _in_adr_type; + +public: + AryEqNode(Node* control, Node* char_array_mem, const TypeAryPtr* in_adr_type, Node* s1, Node* s2, ArgEncoding encoding): - StrIntrinsicNode(control, char_array_mem, s1, s2, encoding) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } + StrIntrinsicNode(control, char_array_mem, s1, s2, encoding), _in_adr_type(in_adr_type) {}; + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::BOOL; } + +private: + virtual uint size_of() const override { return sizeof(AryEqNode); } + virtual uint hash() const override { return StrIntrinsicNode::hash() + (uint)(uintptr_t) _in_adr_type; } + virtual bool cmp(const Node& n) const override { + return StrIntrinsicNode::cmp(n) && _in_adr_type == static_cast(n)._in_adr_type; + } + virtual const TypePtr* adr_type() const override { return _in_adr_type; } }; //------------------------------CountPositives------------------------------ -class CountPositivesNode: public StrIntrinsicNode { +class CountPositivesNode final : public StrIntrinsicNode { public: CountPositivesNode(Node* control, Node* char_array_mem, Node* s1, Node* c1): StrIntrinsicNode(control, char_array_mem, s1, c1, none) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::POS; } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::POS; } + virtual const TypePtr* adr_type() const override { return TypeAryPtr::BYTES; } }; //------------------------------VectorizedHashCodeNode---------------------- -class VectorizedHashCodeNode: public Node { - public: - VectorizedHashCodeNode(Node* control, Node* ary_mem, Node* arg1, Node* cnt1, Node* result, Node* basic_type) - : Node(control, ary_mem, arg1, cnt1, result, basic_type) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; +class VectorizedHashCodeNode final : public Node { +private: + const TypeAryPtr* const _in_adr_type; + +public: + VectorizedHashCodeNode(Node* control, Node* ary_mem, const TypeAryPtr* in_adr_type, Node* arg1, Node* cnt1, Node* result, Node* basic_type) + : Node(control, ary_mem, arg1, cnt1, result, basic_type), _in_adr_type(in_adr_type) {}; + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual uint match_edge(uint idx) const override; + virtual uint ideal_reg() const override { return Op_RegI; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + virtual const Type* Value(PhaseGVN* phase) const override; private: - virtual bool depends_only_on_test_impl() const { return false; } + virtual uint size_of() const override { return sizeof(VectorizedHashCodeNode); } + virtual uint hash() const override { return Node::hash() + (uint)(uintptr_t) _in_adr_type; } + virtual bool cmp(const Node& n) const override { + return Node::cmp(n) && _in_adr_type == static_cast(n)._in_adr_type; + } + virtual const TypePtr* adr_type() const override { return _in_adr_type; } + virtual bool depends_only_on_test_impl() const override { return false; } }; //------------------------------EncodeISOArray-------------------------------- // encode char[] to byte[] in ISO_8859_1 or ASCII -class EncodeISOArrayNode: public Node { +class EncodeISOArrayNode final : public Node { +private: + const TypePtr* const _adr_type; bool _ascii; - public: - EncodeISOArrayNode(Node* control, Node* arymem, Node* s1, Node* s2, Node* c, bool ascii) - : Node(control, arymem, s1, s2, c), _ascii(ascii) {} + +public: + EncodeISOArrayNode(Node* control, Node* arymem, const TypePtr* adr_type, Node* s1, Node* s2, Node* c, bool ascii) + : Node(control, arymem, s1, s2, c), _adr_type(adr_type), _ascii(ascii) {} bool is_ascii() { return _ascii; } - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; - virtual uint size_of() const { return sizeof(EncodeISOArrayNode); } - virtual uint hash() const { return Node::hash() + _ascii; } - virtual bool cmp(const Node& n) const { - return Node::cmp(n) && _ascii == ((EncodeISOArrayNode&)n).is_ascii(); - } + virtual int Opcode() const override; + virtual const Type* bottom_type() const override { return TypeInt::INT; } + virtual uint match_edge(uint idx) const override; + virtual uint ideal_reg() const override { return Op_RegI; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + virtual const Type* Value(PhaseGVN* phase) const override; private: - virtual bool depends_only_on_test_impl() const { return false; } + virtual uint size_of() const override { return sizeof(EncodeISOArrayNode); } + virtual uint hash() const override { return Node::hash() + (uint)(uintptr_t) _adr_type + _ascii; } + virtual bool cmp(const Node& n) const override { + const EncodeISOArrayNode& e = static_cast(n); + return Node::cmp(n) && _ascii == e._ascii && _adr_type == e._adr_type; + } + virtual const TypePtr* adr_type() const override { return _adr_type; } + virtual bool depends_only_on_test_impl() const override { return false; } }; //-------------------------------DigitNode---------------------------------------- diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index bbe3d184c4de..6f4e9d9463df 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1162,7 +1162,7 @@ bool LibraryCallKit::inline_array_equals(StrIntrinsicNode::ArgEnc ae) { Node* arg2 = argument(1); const TypeAryPtr* mtype = (ae == StrIntrinsicNode::UU) ? TypeAryPtr::CHARS : TypeAryPtr::BYTES; - set_result(_gvn.transform(new AryEqNode(control(), memory(mtype), arg1, arg2, ae))); + set_result(_gvn.transform(new AryEqNode(control(), memory(mtype), mtype, arg1, arg2, ae))); clear_upper_avx(); return true; @@ -7254,11 +7254,18 @@ bool LibraryCallKit::inline_encodeISOArray(bool ascii) { // 'src_start' points to src array + scaled offset // 'dst_start' points to dst array + scaled offset - const TypeAryPtr* mtype = TypeAryPtr::BYTES; - Node* enc = new EncodeISOArrayNode(control(), memory(mtype), src_start, dst_start, length, ascii); + // See GraphKit::compress_string + const TypePtr* src_adr_type = TypeAryPtr::get_array_body_type(src_elem); + const TypePtr* dst_adr_type = TypeAryPtr::get_array_body_type(dst_elem); + assert(src_adr_type == TypeAryPtr::BYTES || src_adr_type == TypeAryPtr::CHARS, "unexpected src_adr_type"); + assert(dst_adr_type == TypeAryPtr::BYTES, "unexpected dst_adr_type"); + const TypePtr* adr_type; + Node* mem = capture_memory(adr_type, src_adr_type, dst_adr_type); + Node* enc = new EncodeISOArrayNode(control(), mem, adr_type, src_start, dst_start, length, ascii); enc = _gvn.transform(enc); Node* res_mem = _gvn.transform(new SCMemProjNode(enc)); - set_memory(res_mem, mtype); + memory_effect(res_mem, src_adr_type, dst_adr_type); + set_result(enc); clear_upper_avx(); @@ -7737,7 +7744,8 @@ bool LibraryCallKit::inline_vectorizedHashCode() { // Resolve address of first element Node* array_start = array_element_address(array, offset, bt); - set_result(_gvn.transform(new VectorizedHashCodeNode(control(), memory(TypeAryPtr::get_array_body_type(bt)), + const TypeAryPtr* in_adr_type = TypeAryPtr::get_array_body_type(bt); + set_result(_gvn.transform(new VectorizedHashCodeNode(control(), memory(in_adr_type), in_adr_type, array_start, length, initialValue, basic_type))); clear_upper_avx(); diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestAntiDependency.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestAntiDependency.java new file mode 100644 index 000000000000..341396e56dd7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestAntiDependency.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.intrinsics.string; + +import compiler.lib.ir_framework.DontInline; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8373591 + * @summary Verify that StringLatin1::inflate, StringUTF16::compress, and + * StringCoding::implEncodeAsciiArray are scheduled properly + * @library /test/lib / + * @modules java.base/java.lang:+open + * @run driver ${test.main.class} + */ +public class TestAntiDependency { + static final MethodHandle COMPRESS_HANDLE; + static final MethodHandle INFLATE_HANDLE; + static final MethodHandle ENCODE_ISO_HANDLE; + static { + try { + var currentLookup = MethodHandles.lookup(); + var stringLookup = MethodHandles.privateLookupIn(String.class, currentLookup); + Class stringUtf16Class = stringLookup.findClass("java.lang.StringUTF16"); + var stringUtf16Lookup = MethodHandles.privateLookupIn(stringUtf16Class, currentLookup); + COMPRESS_HANDLE = stringUtf16Lookup.findStatic(stringUtf16Class, "compress0", + MethodType.methodType(int.class, char[].class, int.class, byte[].class, int.class, int.class)); + Class stringLatin1Class = stringLookup.findClass("java.lang.StringLatin1"); + var stringLatin1Lookup = MethodHandles.privateLookupIn(stringLatin1Class, currentLookup); + INFLATE_HANDLE = stringLatin1Lookup.findStatic(stringLatin1Class, "inflate0", + MethodType.methodType(void.class, byte[].class, int.class, char[].class, int.class, int.class)); + Class stringCodingClass = stringLookup.findClass("java.lang.StringCoding"); + ENCODE_ISO_HANDLE = stringLookup.findStatic(stringCodingClass, "encodeAsciiArray0", + MethodType.methodType(int.class, char[].class, int.class, byte[].class, int.class, int.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + var testFramework = new TestFramework(); + testFramework.setDefaultWarmup(1); + testFramework.addFlags("--add-opens=java.base/java.lang=ALL-UNNAMED"); + testFramework.start(); + } + + @DontInline + static void consume(Object o1, Object o2) {} + + @Test + static int testStringCompress() throws Throwable { + byte[] dst = new byte[4]; + char[] src = new char[4]; + consume(dst, src); + dst[0] = (byte) -1; + + // The compiler must not schedule this after the store to src, either by having + // StringCompressedCopyNode kill the whole memory, or by taking into consideration the + // anti-dependency between 2 nodes + int _ = (int) COMPRESS_HANDLE.invokeExact(src, 0, dst, 0, 4); + src[0] = 1; + return dst[0]; + } + + @Test + static int testStringInflate() throws Throwable { + char[] dst = new char[4]; + byte[] src = new byte[4]; + consume(dst, src); + dst[0] = (char) -1; + + // The compiler must not schedule this after the store to src, either by having + // StringInflatedCopyNode kill the whole memory, or by taking into consideration the + // anti-dependency between 2 nodes + INFLATE_HANDLE.invokeExact(src, 0, dst, 0, 4); + src[0] = 1; + return dst[0]; + } + + @Test + static int testEncodeISO() throws Throwable { + byte[] dst = new byte[4]; + char[] src = new char[4]; + consume(dst, src); + dst[0] = (byte) -1; + + // The compiler must not schedule this after the store to src, either by having + // EncodeISOArrayNode kill the whole memory, or by taking into consideration the + // anti-dependency between 2 nodes + int _ = (int) ENCODE_ISO_HANDLE.invokeExact(src, 0, dst, 0, 4); + src[0] = 1; + return dst[0]; + } + + @Run(test = {"testStringCompress", "testStringInflate", "testEncodeISO"}) + public void run() throws Throwable { + Asserts.assertEQ(0, testStringCompress()); + Asserts.assertEQ(0, testStringInflate()); + Asserts.assertEQ(0, testEncodeISO()); + } +} From f90f9b50e1eff97dd18ed1646174ee47c4ebf7a0 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Thu, 27 Aug 2026 09:23:23 +0000 Subject: [PATCH 110/223] 8388369: C2: VectorAPI: Potential null pointer dereference in LibraryCallKit::inline_vector_test Reviewed-by: shade, vlivanov, mchevalier --- src/hotspot/share/opto/vectorIntrinsics.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index d04eda60b81d..f1857409455a 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -1680,16 +1680,22 @@ bool LibraryCallKit::inline_vector_test() { } Node* opd1 = unbox_vector(argument(4), vbox_type, elem_bt, num_elem); + if (opd1 == nullptr) { + log_if_needed(" ** unbox failed m1=%s", NodeClassNames[argument(4)->Opcode()]); + return false; + } + Node* opd2; if (Matcher::vectortest_needs_second_argument(booltest == BoolTest::overflow, opd1->bottom_type()->isa_pvectmask())) { opd2 = unbox_vector(argument(5), vbox_type, elem_bt, num_elem); + if (opd2 == nullptr) { + log_if_needed(" ** unbox failed m2=%s", NodeClassNames[argument(5)->Opcode()]); + return false; + } } else { opd2 = opd1; } - if (opd1 == nullptr || opd2 == nullptr) { - return false; // operand unboxing failed - } Node* cmp = gvn().transform(trace_vector(new VectorTestNode(opd1, opd2, booltest))); BoolTest::mask test = Matcher::vectortest_mask(booltest == BoolTest::overflow, From 23bc7bddb930d5a4126e0b42f858f49a493ca11e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 27 Aug 2026 09:29:48 +0000 Subject: [PATCH 111/223] 8390930: G1: Clearing card table worker estimation overflows on large heaps Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1RemSet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 149f1da1a8bf..70fa7900805a 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -201,8 +201,8 @@ class G1ClearCardTableTask : public G1AbstractSubTask { return AlmostNoWork; } - double num_cards = num_regions << G1HeapRegion::LogCardsPerRegion; - return ceil(num_cards / num_cards_per_worker); + size_t num_cards = (size_t)num_regions << G1HeapRegion::LogCardsPerRegion; + return align_up(num_cards, num_cards_per_worker) / num_cards_per_worker; } virtual ~G1ClearCardTableTask() { From 76e3d4da924101556fe2a4ab84e3980964a28d75 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 27 Aug 2026 10:43:33 +0000 Subject: [PATCH 112/223] 8390938: Shenandoah: Outside-of-cycle cancellation misses GC ID log Reviewed-by: kdnilsen, ogillespie --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 3 ++- .../gc/shenandoah/shenandoahGenerationalControlThread.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 2c82271f07f8..4006b443d14f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -282,7 +282,8 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau // ShenandoahHeap* heap = ShenandoahHeap::heap(); if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) { - log_info(gc, phases)("Cancelled"); + // Need to report at "gc" level to report GC ID proper. + log_info(gc)("Cancelled before cycle started"); return; } heap->increment_total_collections(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index c59f4992a7e2..e5405e1283c2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -403,7 +403,8 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She // acknowledge the cancellation request, the subsequent young cycle will observe // the request and essentially cancel itself. if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) { - log_info(gc, thread)("Preparation for old generation cycle was cancelled"); + // Need to report at "gc" level to report GC ID proper. + log_info(gc)("Preparation for old generation cycle was cancelled"); return; } From 7c2d29789082d03b15861dc85e0d41c66a78e038 Mon Sep 17 00:00:00 2001 From: Xiang Gao Date: Thu, 27 Aug 2026 11:53:40 +0000 Subject: [PATCH 113/223] 8390825: C1: -XX:-GenerateArrayStoreCheck is unsafe and should be removed Reviewed-by: aivy, thartmann, chagedorn --- src/hotspot/share/c1/c1_LIRGenerator.cpp | 2 +- src/hotspot/share/c1/c1_globals.hpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index a4e07cce619c..f61daa556699 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1964,7 +1964,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { } } - if (GenerateArrayStoreCheck && needs_store_check) { + if (needs_store_check) { CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); array_store_check(value.result(), array.result(), store_check_info, x->profiled_method(), x->profiled_bci()); } diff --git a/src/hotspot/share/c1/c1_globals.hpp b/src/hotspot/share/c1/c1_globals.hpp index fad45f747b22..e69883bc436d 100644 --- a/src/hotspot/share/c1/c1_globals.hpp +++ b/src/hotspot/share/c1/c1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,9 +238,6 @@ develop(bool, UseSlowPath, false, \ "For debugging: test slow cases by always using them") \ \ - develop(bool, GenerateArrayStoreCheck, true, \ - "Generates code for array store checks") \ - \ develop(bool, PrintBailouts, false, \ "Print bailout and its reason") \ \ From 8f1f31fa92ea4f7a8bb692911dc1a5c19c726930 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 27 Aug 2026 11:58:53 +0000 Subject: [PATCH 114/223] 8375639: C2: transformation to counted loop in Stemmer.java fails with StressIncrementalInlining Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/ifnode.cpp | 13 +++++ .../TestInnerLoopConstantFoldedExitTest.java | 58 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/longcountedloops/TestInnerLoopConstantFoldedExitTest.java diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index ca7d812c08a9..92c3f66c861b 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1880,6 +1880,19 @@ Node* IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* prev_dom = search_identical(dist, igvn); if (prev_dom != nullptr) { + Node* true_proj = this->true_proj(); + Node* false_proj = this->false_proj(); + + Node* head = true_proj->find_out_with(Op_Loop); + if (head == nullptr) { + head = false_proj->find_out_with(Op_Loop); + } + if (head != nullptr && head->as_Loop()->is_loop_nest_inner_loop()) { + // Exit test for a loop that's in the process of being transformed into a counted loop: do not remove that exit + // test so the counted loop transformation happens. + return nullptr; + } + // Dominating CountedLoopEnd (left over from some now dead loop) will become the new loop exit. Outer strip mined // loop will go away. Mark this loop as no longer strip mined. if (is_CountedLoopEnd()) { diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestInnerLoopConstantFoldedExitTest.java b/test/hotspot/jtreg/compiler/longcountedloops/TestInnerLoopConstantFoldedExitTest.java new file mode 100644 index 000000000000..485728adf512 --- /dev/null +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestInnerLoopConstantFoldedExitTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8375639 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=1 -XX:+AlwaysIncrementalInline + * -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::test ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.longcountedloops; + +public class TestInnerLoopConstantFoldedExitTest { + static int offset = 1; + static final char[] array = {'a', 'b'}; + + static void loop(String s, int off) { + for (int i = 0; i < 2; i++) { + if (array[off + i] != s.charAt(i)) { + return; + } + } + } + + static void test() { + int start = offset - 1; + loop("cd", start); + loop("ab", start); + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; i++) { + test(); + } + } +} + From c64461159c8c8c181109b3423bded3d17b270141 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 27 Aug 2026 12:03:59 +0000 Subject: [PATCH 115/223] 8369828: Generalize share/utilities/bytes.hpp Co-authored-by: Justin King Reviewed-by: aboldtch, cnorrbin, kbarrett --- src/hotspot/cpu/aarch64/bytes_aarch64.hpp | 57 ---- src/hotspot/cpu/arm/bytes_arm.hpp | 180 ------------ src/hotspot/cpu/ppc/bytes_ppc.hpp | 260 ------------------ src/hotspot/cpu/riscv/bytes_riscv.hpp | 167 ----------- src/hotspot/cpu/s390/bytes_s390.hpp | 63 ----- src/hotspot/cpu/x86/bytes_x86.hpp | 101 ------- src/hotspot/cpu/zero/bytes_zero.hpp | 145 ---------- src/hotspot/share/utilities/bytes.hpp | 58 +++- .../share/utilities/unalignedAccess.hpp | 175 ++++++++++++ 9 files changed, 230 insertions(+), 976 deletions(-) delete mode 100644 src/hotspot/cpu/aarch64/bytes_aarch64.hpp delete mode 100644 src/hotspot/cpu/arm/bytes_arm.hpp delete mode 100644 src/hotspot/cpu/ppc/bytes_ppc.hpp delete mode 100644 src/hotspot/cpu/riscv/bytes_riscv.hpp delete mode 100644 src/hotspot/cpu/s390/bytes_s390.hpp delete mode 100644 src/hotspot/cpu/x86/bytes_x86.hpp delete mode 100644 src/hotspot/cpu/zero/bytes_zero.hpp create mode 100644 src/hotspot/share/utilities/unalignedAccess.hpp diff --git a/src/hotspot/cpu/aarch64/bytes_aarch64.hpp b/src/hotspot/cpu/aarch64/bytes_aarch64.hpp deleted file mode 100644 index 6d4a18d00b5f..000000000000 --- a/src/hotspot/cpu/aarch64/bytes_aarch64.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_AARCH64_BYTES_AARCH64_HPP -#define CPU_AARCH64_BYTES_AARCH64_HPP - -#include "memory/allStatic.hpp" -#include "utilities/byteswap.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering - // (no special code is needed since x86 CPUs can access unaligned data) - static inline u2 get_native_u2(address p) { return *(u2*)p; } - static inline u4 get_native_u4(address p) { return *(u4*)p; } - static inline u8 get_native_u8(address p) { return *(u8*)p; } - - static inline void put_native_u2(address p, u2 x) { *(u2*)p = x; } - static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; } - static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; } - - - // Efficient reading and writing of unaligned unsigned data in Java - // byte ordering (i.e. big-endian ordering). Byte-order reversal is - // needed since x86 CPUs use little-endian format. - static inline u2 get_Java_u2(address p) { return byteswap(get_native_u2(p)); } - static inline u4 get_Java_u4(address p) { return byteswap(get_native_u4(p)); } - static inline u8 get_Java_u8(address p) { return byteswap(get_native_u8(p)); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, byteswap(x)); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, byteswap(x)); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, byteswap(x)); } -}; - -#endif // CPU_AARCH64_BYTES_AARCH64_HPP diff --git a/src/hotspot/cpu/arm/bytes_arm.hpp b/src/hotspot/cpu/arm/bytes_arm.hpp deleted file mode 100644 index 6ebf5a61e4f7..000000000000 --- a/src/hotspot/cpu/arm/bytes_arm.hpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_ARM_BYTES_ARM_HPP -#define CPU_ARM_BYTES_ARM_HPP - -#include "memory/allStatic.hpp" -#include "utilities/macros.hpp" - -#ifndef VM_LITTLE_ENDIAN -#define VM_LITTLE_ENDIAN 1 -#endif - -class Bytes: AllStatic { - - public: - static inline u2 get_Java_u2(address p) { - return (u2(p[0]) << 8) | u2(p[1]); - } - - static inline u4 get_Java_u4(address p) { - return u4(p[0]) << 24 | - u4(p[1]) << 16 | - u4(p[2]) << 8 | - u4(p[3]); - } - - static inline u8 get_Java_u8(address p) { - return u8(p[0]) << 56 | - u8(p[1]) << 48 | - u8(p[2]) << 40 | - u8(p[3]) << 32 | - u8(p[4]) << 24 | - u8(p[5]) << 16 | - u8(p[6]) << 8 | - u8(p[7]); - } - - static inline void put_Java_u2(address p, u2 x) { - p[0] = x >> 8; - p[1] = x; - } - - static inline void put_Java_u4(address p, u4 x) { - ((u1*)p)[0] = x >> 24; - ((u1*)p)[1] = x >> 16; - ((u1*)p)[2] = x >> 8; - ((u1*)p)[3] = x; - } - - static inline void put_Java_u8(address p, u8 x) { - ((u1*)p)[0] = x >> 56; - ((u1*)p)[1] = x >> 48; - ((u1*)p)[2] = x >> 40; - ((u1*)p)[3] = x >> 32; - ((u1*)p)[4] = x >> 24; - ((u1*)p)[5] = x >> 16; - ((u1*)p)[6] = x >> 8; - ((u1*)p)[7] = x; - } - -#ifdef VM_LITTLE_ENDIAN - - static inline u2 get_native_u2(address p) { - return (intptr_t(p) & 1) == 0 ? *(u2*)p : u2(p[0]) | (u2(p[1]) << 8); - } - - static inline u4 get_native_u4(address p) { - switch (intptr_t(p) & 3) { - case 0: return *(u4*)p; - case 2: return u4(((u2*)p)[0]) | - u4(((u2*)p)[1]) << 16; - default: return u4(p[0]) | - u4(p[1]) << 8 | - u4(p[2]) << 16 | - u4(p[3]) << 24; - } - } - - static inline u8 get_native_u8(address p) { - switch (intptr_t(p) & 7) { - case 0: return *(u8*)p; - case 4: return u8(((u4*)p)[0]) | - u8(((u4*)p)[1]) << 32; - case 2: return u8(((u2*)p)[0]) | - u8(((u2*)p)[1]) << 16 | - u8(((u2*)p)[2]) << 32 | - u8(((u2*)p)[3]) << 48; - default: return u8(p[0]) | - u8(p[1]) << 8 | - u8(p[2]) << 16 | - u8(p[3]) << 24 | - u8(p[4]) << 32 | - u8(p[5]) << 40 | - u8(p[6]) << 48 | - u8(p[7]) << 56; - } - } - - static inline void put_native_u2(address p, u2 x) { - if ((intptr_t(p) & 1) == 0) { - *(u2*)p = x; - } else { - p[0] = x; - p[1] = x >> 8; - } - } - - static inline void put_native_u4(address p, u4 x) { - switch (intptr_t(p) & 3) { - case 0: *(u4*)p = x; - break; - case 2: ((u2*)p)[0] = x; - ((u2*)p)[1] = x >> 16; - break; - default: ((u1*)p)[0] = x; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[3] = x >> 24; - break; - } - } - - static inline void put_native_u8(address p, u8 x) { - switch (intptr_t(p) & 7) { - case 0: *(u8*)p = x; - break; - case 4: ((u4*)p)[0] = x; - ((u4*)p)[1] = x >> 32; - break; - case 2: ((u2*)p)[0] = x; - ((u2*)p)[1] = x >> 16; - ((u2*)p)[2] = x >> 32; - ((u2*)p)[3] = x >> 48; - break; - default: ((u1*)p)[0] = x; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[3] = x >> 24; - ((u1*)p)[4] = x >> 32; - ((u1*)p)[5] = x >> 40; - ((u1*)p)[6] = x >> 48; - ((u1*)p)[7] = x >> 56; - } - } - -#else - - static inline u2 get_native_u2(address p) { return get_Java_u2(p); } - static inline u4 get_native_u4(address p) { return get_Java_u4(p); } - static inline u8 get_native_u8(address p) { return get_Java_u8(p); } - static inline void put_native_u2(address p, u2 x) { put_Java_u2(p, x); } - static inline void put_native_u4(address p, u4 x) { put_Java_u4(p, x); } - static inline void put_native_u8(address p, u8 x) { put_Java_u8(p, x); } - -#endif // VM_LITTLE_ENDIAN -}; - -#endif // CPU_ARM_BYTES_ARM_HPP diff --git a/src/hotspot/cpu/ppc/bytes_ppc.hpp b/src/hotspot/cpu/ppc/bytes_ppc.hpp deleted file mode 100644 index d6076a9c5b2e..000000000000 --- a/src/hotspot/cpu/ppc/bytes_ppc.hpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2022 SAP SE. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_PPC_BYTES_PPC_HPP -#define CPU_PPC_BYTES_PPC_HPP - -#include "memory/allStatic.hpp" -#include "utilities/byteswap.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering - // PowerPC needs to check for alignment. - - // Can I count on address always being a pointer to an unsigned char? Yes. - -#if defined(VM_LITTLE_ENDIAN) - - static inline u2 get_native_u2(address p) { - return (intptr_t(p) & 1) == 0 - ? *(u2*)p - : ( u2(p[1]) << 8 ) - | ( u2(p[0]) ); - } - - static inline u4 get_native_u4(address p) { - switch (intptr_t(p) & 3) { - case 0: return *(u4*)p; - - case 2: return ( u4( ((u2*)p)[1] ) << 16 ) - | ( u4( ((u2*)p)[0] ) ); - - default: return ( u4(p[3]) << 24 ) - | ( u4(p[2]) << 16 ) - | ( u4(p[1]) << 8 ) - | u4(p[0]); - } - } - - static inline u8 get_native_u8(address p) { - switch (intptr_t(p) & 7) { - case 0: return *(u8*)p; - - case 4: return ( u8( ((u4*)p)[1] ) << 32 ) - | ( u8( ((u4*)p)[0] ) ); - - case 2: return ( u8( ((u2*)p)[3] ) << 48 ) - | ( u8( ((u2*)p)[2] ) << 32 ) - | ( u8( ((u2*)p)[1] ) << 16 ) - | ( u8( ((u2*)p)[0] ) ); - - default: return ( u8(p[7]) << 56 ) - | ( u8(p[6]) << 48 ) - | ( u8(p[5]) << 40 ) - | ( u8(p[4]) << 32 ) - | ( u8(p[3]) << 24 ) - | ( u8(p[2]) << 16 ) - | ( u8(p[1]) << 8 ) - | u8(p[0]); - } - } - - - - static inline void put_native_u2(address p, u2 x) { - if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x; - else { - p[1] = x >> 8; - p[0] = x; - } - } - - static inline void put_native_u4(address p, u4 x) { - switch ( intptr_t(p) & 3 ) { - case 0: *(u4*)p = x; - break; - - case 2: ((u2*)p)[1] = x >> 16; - ((u2*)p)[0] = x; - break; - - default: ((u1*)p)[3] = x >> 24; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[0] = x; - break; - } - } - - static inline void put_native_u8(address p, u8 x) { - switch ( intptr_t(p) & 7 ) { - case 0: *(u8*)p = x; - break; - - case 4: ((u4*)p)[1] = x >> 32; - ((u4*)p)[0] = x; - break; - - case 2: ((u2*)p)[3] = x >> 48; - ((u2*)p)[2] = x >> 32; - ((u2*)p)[1] = x >> 16; - ((u2*)p)[0] = x; - break; - - default: ((u1*)p)[7] = x >> 56; - ((u1*)p)[6] = x >> 48; - ((u1*)p)[5] = x >> 40; - ((u1*)p)[4] = x >> 32; - ((u1*)p)[3] = x >> 24; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[0] = x; - } - } - - // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) - // (no byte-order reversal is needed since Power CPUs are big-endian oriented). - static inline u2 get_Java_u2(address p) { return byteswap(get_native_u2(p)); } - static inline u4 get_Java_u4(address p) { return byteswap(get_native_u4(p)); } - static inline u8 get_Java_u8(address p) { return byteswap(get_native_u8(p)); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, byteswap(x)); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, byteswap(x)); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, byteswap(x)); } - -#else // !defined(VM_LITTLE_ENDIAN) - - static inline u2 get_native_u2(address p) { - return (intptr_t(p) & 1) == 0 - ? *(u2*)p - : ( u2(p[0]) << 8 ) - | ( u2(p[1]) ); - } - - static inline u4 get_native_u4(address p) { - switch (intptr_t(p) & 3) { - case 0: return *(u4*)p; - - case 2: return ( u4( ((u2*)p)[0] ) << 16 ) - | ( u4( ((u2*)p)[1] ) ); - - default: return ( u4(p[0]) << 24 ) - | ( u4(p[1]) << 16 ) - | ( u4(p[2]) << 8 ) - | u4(p[3]); - } - } - - static inline u8 get_native_u8(address p) { - switch (intptr_t(p) & 7) { - case 0: return *(u8*)p; - - case 4: return ( u8( ((u4*)p)[0] ) << 32 ) - | ( u8( ((u4*)p)[1] ) ); - - case 2: return ( u8( ((u2*)p)[0] ) << 48 ) - | ( u8( ((u2*)p)[1] ) << 32 ) - | ( u8( ((u2*)p)[2] ) << 16 ) - | ( u8( ((u2*)p)[3] ) ); - - default: return ( u8(p[0]) << 56 ) - | ( u8(p[1]) << 48 ) - | ( u8(p[2]) << 40 ) - | ( u8(p[3]) << 32 ) - | ( u8(p[4]) << 24 ) - | ( u8(p[5]) << 16 ) - | ( u8(p[6]) << 8 ) - | u8(p[7]); - } - } - - - - static inline void put_native_u2(address p, u2 x) { - if ( (intptr_t(p) & 1) == 0 ) { *(u2*)p = x; } - else { - p[0] = x >> 8; - p[1] = x; - } - } - - static inline void put_native_u4(address p, u4 x) { - switch ( intptr_t(p) & 3 ) { - case 0: *(u4*)p = x; - break; - - case 2: ((u2*)p)[0] = x >> 16; - ((u2*)p)[1] = x; - break; - - default: ((u1*)p)[0] = x >> 24; - ((u1*)p)[1] = x >> 16; - ((u1*)p)[2] = x >> 8; - ((u1*)p)[3] = x; - break; - } - } - - static inline void put_native_u8(address p, u8 x) { - switch ( intptr_t(p) & 7 ) { - case 0: *(u8*)p = x; - break; - - case 4: ((u4*)p)[0] = x >> 32; - ((u4*)p)[1] = x; - break; - - case 2: ((u2*)p)[0] = x >> 48; - ((u2*)p)[1] = x >> 32; - ((u2*)p)[2] = x >> 16; - ((u2*)p)[3] = x; - break; - - default: ((u1*)p)[0] = x >> 56; - ((u1*)p)[1] = x >> 48; - ((u1*)p)[2] = x >> 40; - ((u1*)p)[3] = x >> 32; - ((u1*)p)[4] = x >> 24; - ((u1*)p)[5] = x >> 16; - ((u1*)p)[6] = x >> 8; - ((u1*)p)[7] = x; - } - } - - // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) - // (no byte-order reversal is needed since Power CPUs are big-endian oriented). - static inline u2 get_Java_u2(address p) { return get_native_u2(p); } - static inline u4 get_Java_u4(address p) { return get_native_u4(p); } - static inline u8 get_Java_u8(address p) { return get_native_u8(p); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } - -#endif // VM_LITTLE_ENDIAN -}; - -#endif // CPU_PPC_BYTES_PPC_HPP diff --git a/src/hotspot/cpu/riscv/bytes_riscv.hpp b/src/hotspot/cpu/riscv/bytes_riscv.hpp deleted file mode 100644 index 9495703a03f8..000000000000 --- a/src/hotspot/cpu/riscv/bytes_riscv.hpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. - * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_RISCV_BYTES_RISCV_HPP -#define CPU_RISCV_BYTES_RISCV_HPP - -#include "memory/allStatic.hpp" -#include "utilities/byteswap.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering - // RISCV needs to check for alignment. - - static inline u2 get_native_u2(address p) { - if ((intptr_t(p) & 1) == 0) { - return *(u2*)p; - } else { - return ((u2)(p[1]) << 8) | - ((u2)(p[0])); - } - } - - static inline u4 get_native_u4(address p) { - switch (intptr_t(p) & 3) { - case 0: - return *(u4*)p; - - case 2: - return ((u4)(((u2*)p)[1]) << 16) | - ((u4)(((u2*)p)[0])); - - default: - return ((u4)(p[3]) << 24) | - ((u4)(p[2]) << 16) | - ((u4)(p[1]) << 8) | - ((u4)(p[0])); - } - } - - static inline u8 get_native_u8(address p) { - switch (intptr_t(p) & 7) { - case 0: - return *(u8*)p; - - case 4: - return ((u8)(((u4*)p)[1]) << 32) | - ((u8)(((u4*)p)[0])); - - case 2: - case 6: - return ((u8)(((u2*)p)[3]) << 48) | - ((u8)(((u2*)p)[2]) << 32) | - ((u8)(((u2*)p)[1]) << 16) | - ((u8)(((u2*)p)[0])); - - default: - return ((u8)(p[7]) << 56) | - ((u8)(p[6]) << 48) | - ((u8)(p[5]) << 40) | - ((u8)(p[4]) << 32) | - ((u8)(p[3]) << 24) | - ((u8)(p[2]) << 16) | - ((u8)(p[1]) << 8) | - ((u8)(p[0])); - } - } - - static inline void put_native_u2(address p, u2 x) { - if ((intptr_t(p) & 1) == 0) { - *(u2*)p = x; - } else { - p[1] = x >> 8; - p[0] = x; - } - } - - static inline void put_native_u4(address p, u4 x) { - switch (intptr_t(p) & 3) { - case 0: - *(u4*)p = x; - break; - - case 2: - ((u2*)p)[1] = x >> 16; - ((u2*)p)[0] = x; - break; - - default: - ((u1*)p)[3] = x >> 24; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[0] = x; - break; - } - } - - static inline void put_native_u8(address p, u8 x) { - switch (intptr_t(p) & 7) { - case 0: - *(u8*)p = x; - break; - - case 4: - ((u4*)p)[1] = x >> 32; - ((u4*)p)[0] = x; - break; - - case 2: - case 6: - ((u2*)p)[3] = x >> 48; - ((u2*)p)[2] = x >> 32; - ((u2*)p)[1] = x >> 16; - ((u2*)p)[0] = x; - break; - - default: - ((u1*)p)[7] = x >> 56; - ((u1*)p)[6] = x >> 48; - ((u1*)p)[5] = x >> 40; - ((u1*)p)[4] = x >> 32; - ((u1*)p)[3] = x >> 24; - ((u1*)p)[2] = x >> 16; - ((u1*)p)[1] = x >> 8; - ((u1*)p)[0] = x; - break; - } - } - -#ifndef VM_LITTLE_ENDIAN -#error RISC-V is little endian, the preprocessor macro VM_LITTLE_ENDIAN should be defined. -#endif - - // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) - static inline u2 get_Java_u2(address p) { return byteswap(get_native_u2(p)); } - static inline u4 get_Java_u4(address p) { return byteswap(get_native_u4(p)); } - static inline u8 get_Java_u8(address p) { return byteswap(get_native_u8(p)); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, byteswap(x)); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, byteswap(x)); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, byteswap(x)); } -}; - -#endif // CPU_RISCV_BYTES_RISCV_HPP diff --git a/src/hotspot/cpu/s390/bytes_s390.hpp b/src/hotspot/cpu/s390/bytes_s390.hpp deleted file mode 100644 index ed6418bd4511..000000000000 --- a/src/hotspot/cpu/s390/bytes_s390.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2022 SAP SE. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_S390_BYTES_S390_HPP -#define CPU_S390_BYTES_S390_HPP - -#include "memory/allStatic.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in - // platform-specific byte ordering. - - // Use regular load and store for unaligned access. - // - // On z/Architecture, unaligned loads and stores are supported when using the - // "traditional" load (LH, L/LY, LG) and store (STH, ST/STY, STG) instructions. - // The penalty for unaligned access is just very few (two or three) ticks, - // plus another few (two or three) ticks if the access crosses a cache line boundary. - // - // In short, it makes no sense on z/Architecture to piecemeal get or put unaligned data. - - static inline u2 get_native_u2(address p) { return *(u2*)p; } - static inline u4 get_native_u4(address p) { return *(u4*)p; } - static inline u8 get_native_u8(address p) { return *(u8*)p; } - - static inline void put_native_u2(address p, u2 x) { *(u2*)p = x; } - static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; } - static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; } - - // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) - static inline u2 get_Java_u2(address p) { return get_native_u2(p); } - static inline u4 get_Java_u4(address p) { return get_native_u4(p); } - static inline u8 get_Java_u8(address p) { return get_native_u8(p); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } -}; - -#endif // CPU_S390_BYTES_S390_HPP diff --git a/src/hotspot/cpu/x86/bytes_x86.hpp b/src/hotspot/cpu/x86/bytes_x86.hpp deleted file mode 100644 index 3f7f42342600..000000000000 --- a/src/hotspot/cpu/x86/bytes_x86.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1997, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_X86_BYTES_X86_HPP -#define CPU_X86_BYTES_X86_HPP - -#include "memory/allStatic.hpp" -#include "utilities/align.hpp" -#include "utilities/byteswap.hpp" -#include "utilities/macros.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering - template - static inline T get_native(const void* p) { - assert(p != nullptr, "null pointer"); - - T x; - - if (is_aligned(p, sizeof(T))) { - x = *(T*)p; - } else { - memcpy(&x, p, sizeof(T)); - } - - return x; - } - - template - static inline void put_native(void* p, T x) { - assert(p != nullptr, "null pointer"); - - if (is_aligned(p, sizeof(T))) { - *(T*)p = x; - } else { - memcpy(p, &x, sizeof(T)); - } - } - - static inline u2 get_native_u2(address p) { return get_native((void*)p); } - static inline u4 get_native_u4(address p) { return get_native((void*)p); } - static inline u8 get_native_u8(address p) { return get_native((void*)p); } - static inline void put_native_u2(address p, u2 x) { put_native((void*)p, x); } - static inline void put_native_u4(address p, u4 x) { put_native((void*)p, x); } - static inline void put_native_u8(address p, u8 x) { put_native((void*)p, x); } - - // Efficient reading and writing of unaligned unsigned data in Java - // byte ordering (i.e. big-endian ordering). Byte-order reversal is - // needed since x86 CPUs use little-endian format. - template - static inline T get_Java(const address p) { - T x = get_native(p); - - if (Endian::is_Java_byte_ordering_different()) { - x = byteswap(x); - } - - return x; - } - - template - static inline void put_Java(address p, T x) { - if (Endian::is_Java_byte_ordering_different()) { - x = byteswap(x); - } - - put_native(p, x); - } - - static inline u2 get_Java_u2(address p) { return get_Java(p); } - static inline u4 get_Java_u4(address p) { return get_Java(p); } - static inline u8 get_Java_u8(address p) { return get_Java(p); } - - static inline void put_Java_u2(address p, u2 x) { put_Java(p, x); } - static inline void put_Java_u4(address p, u4 x) { put_Java(p, x); } - static inline void put_Java_u8(address p, u8 x) { put_Java(p, x); } -}; - -#endif // CPU_X86_BYTES_X86_HPP diff --git a/src/hotspot/cpu/zero/bytes_zero.hpp b/src/hotspot/cpu/zero/bytes_zero.hpp deleted file mode 100644 index 15d0fc32650f..000000000000 --- a/src/hotspot/cpu/zero/bytes_zero.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2009 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_ZERO_BYTES_ZERO_HPP -#define CPU_ZERO_BYTES_ZERO_HPP - -#include "memory/allStatic.hpp" - -typedef union unaligned { - u4 u; - u2 us; - u8 ul; -} __attribute__((packed)) unaligned; - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in - // platform-specific byte ordering. - static inline u2 get_native_u2(address p){ - unaligned *up = (unaligned *) p; - return up->us; - } - - static inline u4 get_native_u4(address p) { - unaligned *up = (unaligned *) p; - return up->u; - } - - static inline u8 get_native_u8(address p) { - unaligned *up = (unaligned *) p; - return up->ul; - } - - static inline void put_native_u2(address p, u2 x) { - unaligned *up = (unaligned *) p; - up->us = x; - } - - static inline void put_native_u4(address p, u4 x) { - unaligned *up = (unaligned *) p; - up->u = x; - } - - static inline void put_native_u8(address p, u8 x) { - unaligned *up = (unaligned *) p; - up->ul = x; - } - - // Efficient reading and writing of unaligned unsigned data in Java - // byte ordering (i.e. big-endian ordering). -#ifdef VM_LITTLE_ENDIAN - // Byte-order reversal is needed - static inline u2 get_Java_u2(address p) { - return (u2(p[0]) << 8) | - (u2(p[1]) ); - } - static inline u4 get_Java_u4(address p) { - return (u4(p[0]) << 24) | - (u4(p[1]) << 16) | - (u4(p[2]) << 8) | - (u4(p[3]) ); - } - static inline u8 get_Java_u8(address p) { - u4 hi, lo; - hi = (u4(p[0]) << 24) | - (u4(p[1]) << 16) | - (u4(p[2]) << 8) | - (u4(p[3]) ); - lo = (u4(p[4]) << 24) | - (u4(p[5]) << 16) | - (u4(p[6]) << 8) | - (u4(p[7]) ); - return u8(lo) | (u8(hi) << 32); - } - - static inline void put_Java_u2(address p, u2 x) { - p[0] = x >> 8; - p[1] = x; - } - static inline void put_Java_u4(address p, u4 x) { - p[0] = x >> 24; - p[1] = x >> 16; - p[2] = x >> 8; - p[3] = x; - } - static inline void put_Java_u8(address p, u8 x) { - u4 hi, lo; - lo = x; - hi = x >> 32; - p[0] = hi >> 24; - p[1] = hi >> 16; - p[2] = hi >> 8; - p[3] = hi; - p[4] = lo >> 24; - p[5] = lo >> 16; - p[6] = lo >> 8; - p[7] = lo; - } -#else - // No byte-order reversal is needed - static inline u2 get_Java_u2(address p) { - return get_native_u2(p); - } - static inline u4 get_Java_u4(address p) { - return get_native_u4(p); - } - static inline u8 get_Java_u8(address p) { - return get_native_u8(p); - } - - static inline void put_Java_u2(address p, u2 x) { - put_native_u2(p, x); - } - static inline void put_Java_u4(address p, u4 x) { - put_native_u4(p, x); - } - static inline void put_Java_u8(address p, u8 x) { - put_native_u8(p, x); - } -#endif // VM_LITTLE_ENDIAN -}; - -#endif // CPU_ZERO_BYTES_ZERO_HPP diff --git a/src/hotspot/share/utilities/bytes.hpp b/src/hotspot/share/utilities/bytes.hpp index 99f3c9749bf7..03c0a6566d41 100644 --- a/src/hotspot/share/utilities/bytes.hpp +++ b/src/hotspot/share/utilities/bytes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,10 @@ #ifndef SHARE_UTILITIES_BYTES_HPP #define SHARE_UTILITIES_BYTES_HPP -#include "utilities/macros.hpp" +#include "memory/allStatic.hpp" +#include "utilities/byteswap.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/unalignedAccess.hpp" class Endian : AllStatic { public: @@ -48,6 +51,55 @@ class Endian : AllStatic { } }; -#include CPU_HEADER(bytes) +class Bytes : AllStatic { + public: + // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering. + template + static inline T get_native(const void* p) { + return UnalignedAccess::load(p); + } + + template + static inline void put_native(void* p, T x) { + UnalignedAccess::store(p, x); + } + + static inline u2 get_native_u2(address p) { return get_native(p); } + static inline u4 get_native_u4(address p) { return get_native(p); } + static inline u8 get_native_u8(address p) { return get_native(p); } + static inline void put_native_u2(address p, u2 x) { put_native(p, x); } + static inline void put_native_u4(address p, u4 x) { put_native(p, x); } + static inline void put_native_u8(address p, u8 x) { put_native(p, x); } + + // Efficient reading and writing of unaligned unsigned data in Java + // byte ordering (i.e. big-endian ordering). + template + static inline T get_Java(const address p) { + T x = get_native(p); + + if (Endian::is_Java_byte_ordering_different()) { + x = byteswap(x); + } + + return x; + } + + template + static inline void put_Java(address p, T x) { + if (Endian::is_Java_byte_ordering_different()) { + x = byteswap(x); + } + + put_native(p, x); + } + + static inline u2 get_Java_u2(address p) { return get_Java(p); } + static inline u4 get_Java_u4(address p) { return get_Java(p); } + static inline u8 get_Java_u8(address p) { return get_Java(p); } + + static inline void put_Java_u2(address p, u2 x) { put_Java(p, x); } + static inline void put_Java_u4(address p, u4 x) { put_Java(p, x); } + static inline void put_Java_u8(address p, u8 x) { put_Java(p, x); } +}; #endif // SHARE_UTILITIES_BYTES_HPP diff --git a/src/hotspot/share/utilities/unalignedAccess.hpp b/src/hotspot/share/utilities/unalignedAccess.hpp new file mode 100644 index 000000000000..dd18381e9275 --- /dev/null +++ b/src/hotspot/share/utilities/unalignedAccess.hpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025 Google and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_UTILITIES_UNALIGNED_ACCESS_HPP +#define SHARE_UTILITIES_UNALIGNED_ACCESS_HPP + +#include "memory/allStatic.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef ADDRESS_SANITIZER +// ASan, HWAsan, MSan, and TSan have special support for unaligned access. +// If we ever support the others, update the above ifdef. +#define SANITIZER_HAS_UNALIGNED_ACCESS 1 +#endif + +#ifdef SANITIZER_HAS_UNALIGNED_ACCESS +#include +#endif + +#include +#include +#include + +// Provides access to unaligned data. +class UnalignedAccess : AllStatic { + public: + template + static void store(void* ptr, T value) { + static_assert(std::is_trivially_copyable::value); + assert(ptr != nullptr, "nullptr"); + StoreImpl{}(static_cast(ptr), value); + } + + template + static T load(const void* ptr) { + static_assert(std::is_trivially_copyable::value); + assert(ptr != nullptr, "nullptr"); + return LoadImpl{}(static_cast(ptr)); + } + + private: + template struct StoreImpl; + template struct LoadImpl; +}; + +template<> +struct UnalignedAccess::StoreImpl<1> { + template + void operator()(T* ptr, T value) const { + static_assert(sizeof(T) == sizeof(uint8_t)); + *ptr = value; + } +}; + +template<> +struct UnalignedAccess::LoadImpl<1> { + template + T operator()(const T* ptr) const { + static_assert(sizeof(T) == sizeof(uint8_t)); + return *ptr; + } +}; + +#ifdef SANITIZER_HAS_UNALIGNED_ACCESS +template<> +struct UnalignedAccess::StoreImpl<2> { + template + void operator()(T* ptr, T value) const { + static_assert(sizeof(T) == sizeof(uint16_t)); + __sanitizer_unaligned_store16(ptr, static_cast(value)); + } +}; + +template<> +struct UnalignedAccess::StoreImpl<4> { + template + void operator()(T* ptr, T value) const { + static_assert(sizeof(T) == sizeof(uint32_t)); + __sanitizer_unaligned_store32(ptr, static_cast(value)); + } +}; + +template<> +struct UnalignedAccess::StoreImpl<8> { + template + void operator()(T* ptr, T value) const { + static_assert(sizeof(T) == sizeof(uint64_t)); + __sanitizer_unaligned_store64(ptr, static_cast(value)); + } +}; + +template<> +struct UnalignedAccess::LoadImpl<2> { + template + T operator()(const T* ptr) const { + static_assert(sizeof(T) == sizeof(uint16_t)); + return static_cast(__sanitizer_unaligned_load16(ptr)); + } +}; + +template<> +struct UnalignedAccess::LoadImpl<4> { + template + T operator()(const T* ptr) const { + static_assert(sizeof(T) == sizeof(uint32_t)); + return static_cast(__sanitizer_unaligned_load32(ptr)); + } +}; + +template<> +struct UnalignedAccess::LoadImpl<8> { + template + T operator()(const T* ptr) const { + static_assert(sizeof(T) == sizeof(uint64_t)); + return static_cast(__sanitizer_unaligned_load64(ptr)); + } +}; +#else +template +struct UnalignedAccess::StoreImpl { + template + void operator()(T* ptr, T value) const { + static_assert(sizeof(T) == byte_size); + static_assert(byte_size != 0); // Incomplete type + // The only portable way to implement unaligned stores is to use memcpy. + // Fortunately all decent compilers are able to inline this and avoid + // the actual call to memcpy. On platforms which allow unaligned access, + // the compiler will emit a normal store instruction. + memcpy(ptr, &value, sizeof(T)); + } +}; + +template +struct UnalignedAccess::LoadImpl { + template + T operator()(const T* ptr) const { + static_assert(sizeof(T) == byte_size); + static_assert(byte_size != 0); // Incomplete type + // The only portable way to implement unaligned loads is to use memcpy. + // Fortunately all decent compilers are able to inline this and avoid + // the actual call to memcpy. On platforms which allow unaligned access, + // the compiler will emit a normal load instruction. + T value; + memcpy(&value, ptr, sizeof(T)); + return value; + } +}; +#endif // SANITIZER_HAS_UNALIGNED_ACCESS + +#undef SANITIZER_HAS_UNALIGNED_ACCESS + +#endif // SHARE_UTILITIES_UNALIGNED_ACCESS_HPP From 9c2f6c40ad453db03289a8f85cfec2f91ef5dd55 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Thu, 27 Aug 2026 12:15:56 +0000 Subject: [PATCH 116/223] 8390870: ForkJoinTask.get(long, TimeUnit) stuck in busy-wait with another waiter Reviewed-by: vklang --- .../java/util/concurrent/ForkJoinTask.java | 2 +- .../forkjoin/GetMultipleWaiters.java | 115 ++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/util/concurrent/forkjoin/GetMultipleWaiters.java diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index f39d92aeeb40..b985c4eb4b82 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -448,7 +448,7 @@ else if (deadline != 0L) { Aux next = a.next; if (a == node) { if (prev != null) - prev.casNext(prev, next); + prev.casNext(a, next); else if (casAux(a, next)) break clean; break; // check for failed or stale CAS diff --git a/test/jdk/java/util/concurrent/forkjoin/GetMultipleWaiters.java b/test/jdk/java/util/concurrent/forkjoin/GetMultipleWaiters.java new file mode 100644 index 000000000000..d595747b65d4 --- /dev/null +++ b/test/jdk/java/util/concurrent/forkjoin/GetMultipleWaiters.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8390870 + * @summary ForkJoinTask.get must honor its timeout and interrupts even + * when another thread is waiting on the same task. + * @run junit/othervm/timeout=20 GetMultipleWaiters + */ + +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +class GetMultipleWaiters { + + /** + * get() must be interruptible while another thread is waiting on the + * same task. + */ + @Test + void testGet() throws Exception { + var task = ForkJoinTask.adapt(() -> {}); + var thrown = new Throwable[1]; + + var a = startThreadAndAwaitState(() -> { + try { + task.get(); + } catch (Throwable t) { + thrown[0] = t; + } + }, "Get-waiter-A", Thread.State.WAITING); + var b = startThreadAndAwaitState(() -> { + try { + task.get(); + } catch (Throwable ignore) { + } + }, "Get-waiter-B", Thread.State.WAITING); + + try { + a.interrupt(); + a.join(); + + assertInstanceOf(InterruptedException.class, thrown[0]); + } finally { + task.complete(null); + b.join(); + } + } + + /** + * get(long, TimeUnit) must time out while another thread is waiting + * on the same task. + */ + @Test + void testTimedGet() throws Exception { + var task = ForkJoinTask.adapt(() -> {}); + var thrown = new Throwable[1]; + + var a = startThreadAndAwaitState(() -> { + try { + task.get(1, TimeUnit.SECONDS); + } catch (Throwable t) { + thrown[0] = t; + } + }, "TimedGet-waiter-A", Thread.State.TIMED_WAITING); + var b = startThreadAndAwaitState(() -> { + try { + task.get(); + } catch (Throwable ignore) { + } + }, "TimedGet-waiter-B", Thread.State.WAITING); + + try { + a.join(); + + assertInstanceOf(TimeoutException.class, thrown[0]); + } finally { + task.complete(null); + b.join(); + } + } + + static Thread startThreadAndAwaitState(Runnable r, String name, Thread.State state) throws Exception { + var t = new Thread(r, name); + t.start(); + while (t.getState() != state) + Thread.sleep(1); + return t; + } +} From 2f08c72eb4de9d1096ee41ea92e0d9113a56d86c Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 27 Aug 2026 13:11:41 +0000 Subject: [PATCH 117/223] 8391220: Rewriter has unused _invokedynamic_references_map Reviewed-by: cnorrbin, matsaave --- src/hotspot/share/interpreter/rewriter.cpp | 15 ++++++++------- src/hotspot/share/interpreter/rewriter.hpp | 9 ++------- src/hotspot/share/oops/cpCache.cpp | 3 +-- src/hotspot/share/oops/cpCache.hpp | 6 +----- src/hotspot/share/oops/cpCache.inline.hpp | 3 +-- 5 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index f6422e123c40..1353fda40c59 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,8 +109,10 @@ void Rewriter::make_constant_pool_cache(TRAPS) { assert(_field_entry_index == _initialized_field_entries.length(), "Field entry size mismatch"); assert(_method_entry_index == _initialized_method_entries.length(), "Method entry size mismatch"); ConstantPoolCache* cache = - ConstantPoolCache::allocate(loader_data, _invokedynamic_references_map, - _initialized_indy_entries, _initialized_field_entries, _initialized_method_entries, + ConstantPoolCache::allocate(loader_data, + _initialized_indy_entries, + _initialized_field_entries, + _initialized_method_entries, CHECK); // initialize object cache in constant pool @@ -255,14 +257,14 @@ void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, int cache_i MethodHandles::is_signature_polymorphic_name(vmClasses::MethodHandle_klass(), _pool->uncached_name_ref_at(cp_index))) { // we may need a resolved_refs entry for the appendix - int resolved_index = add_invokedynamic_resolved_references_entry(cp_index, cache_index); + int resolved_index = add_invokedynamic_resolved_references_entry(cp_index); _initialized_method_entries.at(cache_index).set_resolved_references_index((u2)resolved_index); status = +1; } else if (_pool->uncached_klass_ref_at_noresolve(cp_index) == vmSymbols::java_lang_invoke_VarHandle() && MethodHandles::is_signature_polymorphic_name(vmClasses::VarHandle_klass(), _pool->uncached_name_ref_at(cp_index))) { // we may need a resolved_refs entry for the appendix - int resolved_index = add_invokedynamic_resolved_references_entry(cp_index, cache_index); + int resolved_index = add_invokedynamic_resolved_references_entry(cp_index); _initialized_method_entries.at(cache_index).set_resolved_references_index((u2)resolved_index); status = +1; } else { @@ -294,7 +296,7 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) { assert(p[-1] == Bytecodes::_invokedynamic, "not invokedynamic bytecode"); if (!reverse) { int cp_index = Bytes::get_Java_u2(p); - int resolved_index = add_invokedynamic_resolved_references_entry(cp_index, -1); // Indy no longer has a CPCE + int resolved_index = add_invokedynamic_resolved_references_entry(cp_index); // Indy no longer has a CPCE // Replace the trailing four bytes with an index to the array of // indy resolution information in the CPC. There is one entry for // each bytecode, even if they make the same call. In other words, @@ -584,7 +586,6 @@ Rewriter::Rewriter(InstanceKlass* klass, const constantPoolHandle& cpool, Array< _cp_map(cpool->length()), _reference_map(cpool->length()), _resolved_references_map(cpool->length() / 2), - _invokedynamic_references_map(cpool->length() / 2), _method_handle_invokers(cpool->length()), _invokedynamic_index(0), _field_entry_index(0), diff --git a/src/hotspot/share/interpreter/rewriter.hpp b/src/hotspot/share/interpreter/rewriter.hpp index 92e8e7db5346..0da02dd09074 100644 --- a/src/hotspot/share/interpreter/rewriter.hpp +++ b/src/hotspot/share/interpreter/rewriter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ class Rewriter: public StackObj { GrowableArray _cp_map; GrowableArray _reference_map; // maps from cp index to resolved_refs index (or -1) GrowableArray _resolved_references_map; // for strings, methodHandle, methodType - GrowableArray _invokedynamic_references_map; // for invokedynamic resolved refs GrowableArray _method_handle_invokers; int _resolved_reference_limit; int _invokedynamic_index; @@ -68,7 +67,6 @@ class Rewriter: public StackObj { _method_handle_invokers.trunc_to(0); _resolved_references_map.trunc_to(0); - _invokedynamic_references_map.trunc_to(0); _resolved_reference_limit = -1; } @@ -101,13 +99,10 @@ class Rewriter: public StackObj { } // add a new entry to the resolved_references map (for invokedynamic and invokehandle only) - int add_invokedynamic_resolved_references_entry(int cp_index, int cache_index) { + int add_invokedynamic_resolved_references_entry(int cp_index) { assert(_resolved_reference_limit >= 0, "must add indy refs after first iteration"); int ref_index = _resolved_references_map.append(cp_index); // many-to-one assert(ref_index >= _resolved_reference_limit, ""); - if (_pool->tag_at(cp_index).value() != JVM_CONSTANT_InvokeDynamic) { - _invokedynamic_references_map.at_put_grow(ref_index, cache_index, -1); - } return ref_index; } diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 4b8bcb8e0ef0..5edc9813c9bd 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -376,7 +376,6 @@ Method* ConstantPoolCache::method_if_resolved(int method_index) const { } ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, - const intStack& invokedynamic_map, const GrowableArray indy_entries, const GrowableArray field_entries, const GrowableArray method_entries, @@ -390,7 +389,7 @@ ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, Array* resolved_method_entries = initialize_resolved_entries_array(loader_data, method_entries, CHECK_NULL); return new (loader_data, size, MetaspaceObj::ConstantPoolCacheType, THREAD) - ConstantPoolCache(invokedynamic_map, resolved_indy_entries, resolved_field_entries, resolved_method_entries); + ConstantPoolCache(resolved_indy_entries, resolved_field_entries, resolved_method_entries); } // Record the GC marking cycle when redefined vs. when found in the loom stack chunks. diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 1a331e703b4d..7f4532f99143 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -91,16 +91,12 @@ class ConstantPoolCache: public MetaspaceObj { }; // Constructor - ConstantPoolCache(const intStack& invokedynamic_references_map, - Array* indy_info, + ConstantPoolCache(Array* indy_info, Array* field_entries, Array* mehtod_entries); - // Initialization - void initialize(const intArray& invokedynamic_references_map); public: static ConstantPoolCache* allocate(ClassLoaderData* loader_data, - const intStack& invokedynamic_references_map, const GrowableArray indy_entries, const GrowableArray field_entries, const GrowableArray method_entries, diff --git a/src/hotspot/share/oops/cpCache.inline.hpp b/src/hotspot/share/oops/cpCache.inline.hpp index fad5931ba180..9d8fbc5be1c6 100644 --- a/src/hotspot/share/oops/cpCache.inline.hpp +++ b/src/hotspot/share/oops/cpCache.inline.hpp @@ -35,8 +35,7 @@ #include "runtime/atomicAccess.hpp" // Constructor -inline ConstantPoolCache::ConstantPoolCache(const intStack& invokedynamic_references_map, - Array* invokedynamic_info, +inline ConstantPoolCache::ConstantPoolCache(Array* invokedynamic_info, Array* field_entries, Array* method_entries) : _constant_pool(nullptr), From 4486eede3355aecf0ced99218bbf27753777a84f Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Thu, 27 Aug 2026 15:04:13 +0000 Subject: [PATCH 118/223] 8388265: early_larval StackMapTable frames not rejected for non-preview class files Co-authored-by: Dan Heidinga Reviewed-by: liach, dholmes, fparain --- src/hotspot/share/classfile/stackMapTable.cpp | 7 +++ src/hotspot/share/classfile/verifier.cpp | 7 ++- src/hotspot/share/classfile/verifier.hpp | 2 + .../verifier/EarlyLarvalNonPreviewApp.jasm | 54 +++++++++++++++++++ .../verifier/EarlyLarvalNonPreviewTest.java | 46 ++++++++++++++++ 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm create mode 100644 test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index 10f49d83b610..8954de5610b0 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -271,6 +271,13 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { VerificationType* locals = nullptr; u1 frame_type = _stream->get_u1(CHECK_NULL); if (frame_type == EARLY_LARVAL) { + // early_larval frames are only supported in classes that support strict fields (preview classes) + if (!Verifier::supports_strict_fields(_verifier->current_class())) { + // reserved frame types when preview classes are disabled + _stream->stackmap_format_error( + "reserved frame type", CHECK_VERIFY_(_verifier, nullptr)); + } + u2 num_unset_fields = _stream->get_u2(CHECK_NULL); StackMapFrame::AssertUnsetFieldTable* new_fields = new StackMapFrame::AssertUnsetFieldTable(); diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index b0ded20b6f8c..626c28c17118 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -636,10 +636,9 @@ TypeOrigin ClassVerifier::ref_ctx(const char* sig) { return TypeOrigin::implicit(vt); } -static bool supports_strict_fields(InstanceKlass* klass) { +bool Verifier::supports_strict_fields(InstanceKlass* klass) { int ver = klass->major_version(); - return ver > Verifier::VALUE_TYPES_MAJOR_VERSION || - (ver == Verifier::VALUE_TYPES_MAJOR_VERSION && klass->minor_version() == Verifier::JAVA_PREVIEW_MINOR_VERSION); + return (ver >= Verifier::VALUE_TYPES_MAJOR_VERSION && klass->minor_version() == Verifier::JAVA_PREVIEW_MINOR_VERSION); } void ClassVerifier::verify_class(TRAPS) { @@ -2428,7 +2427,7 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, } } } - } else if (supports_strict_fields(_klass)) { + } else if (Verifier::supports_strict_fields(_klass)) { // `strict` fields are not writable, but only local fields produce verification errors if (is_local_field && fd.access_flags().is_strict() && fd.access_flags().is_final()) { verify_error(ErrorContext::bad_code(bci), diff --git a/src/hotspot/share/classfile/verifier.hpp b/src/hotspot/share/classfile/verifier.hpp index 087750e4b121..97a546736a4a 100644 --- a/src/hotspot/share/classfile/verifier.hpp +++ b/src/hotspot/share/classfile/verifier.hpp @@ -69,6 +69,8 @@ class Verifier : AllStatic { // Print output for class+resolve static void trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class); + static bool supports_strict_fields(InstanceKlass* klass); + private: static Symbol* inference_verify( InstanceKlass* klass, char* msg, size_t msg_len, TRAPS); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm new file mode 100644 index 000000000000..698332456b6f --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +final identity class EarlyLarvalNonPreviewApp extends java/lang/Record version 72:0 +{ + public final Field x:I; + public final Field y:I; + + public Method "":"(II)V" + stack 2 locals 3 + 0: #{ x } + 1: #{ y } + { + aload_0; + invokespecial Method java/lang/Record."":"()V"; + aload_0; + iload_1; + putfield Field x:"I"; + iload_1; + ifge L16; + iload_2; + ineg; + istore_2; + L16: stack_frame_type early_larval; + unset_fields; + frame_type full; + locals_map class EarlyLarvalNonPreviewApp, int, int; + stack_map; + aload_0; + iload_2; + putfield Field y:"I"; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java new file mode 100644 index 000000000000..79d474620898 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @enablePreview + * @library /test/lib + * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value + * @compile EarlyLarvalNonPreviewApp.jasm + * @run main EarlyLarvalNonPreviewTest + */ + +public class EarlyLarvalNonPreviewTest { + public static void main(String[] args) { + try { + var value = new EarlyLarvalNonPreviewApp(-1, -2); + throw new RuntimeException("Expected ClassFormatError"); + } catch (ClassFormatError c) { + if (!c.getMessage().equals("StackMapTable format error: reserved frame type")) { + throw new RuntimeException("Unexpected ClassFormatError " + c.getMessage()); + } + System.out.println("Test passed"); + } + } +} From 1fb263095da6125005e826185699b78444fb83df Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 27 Aug 2026 15:26:53 +0000 Subject: [PATCH 119/223] 8388138: Emit runtime warning for the RSA/ECB/PKCS1Padding Cipher Reviewed-by: mullan, myankelevich, hchao --- .../share/conf/security/java.security | 2 +- .../TestLegacyCryptoAlgorithms.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/jdk/jdk/security/JavaDotSecurity/TestLegacyCryptoAlgorithms.java diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 74797ed663b0..7f806ed2cf5f 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -845,7 +845,7 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # jdk.crypto.disabledAlgorithms=Cipher.RSA/ECB/PKCS1Padding, MessageDigest.MD2 # jdk.crypto.legacyAlgorithms=Cipher.RSA/ECB/PKCS1Padding, MessageDigest.MD2 # -#jdk.crypto.legacyAlgorithms= +jdk.crypto.legacyAlgorithms=Cipher.RSA/ECB/PKCS1Padding #jdk.crypto.disabledAlgorithms= # diff --git a/test/jdk/jdk/security/JavaDotSecurity/TestLegacyCryptoAlgorithms.java b/test/jdk/jdk/security/JavaDotSecurity/TestLegacyCryptoAlgorithms.java new file mode 100644 index 000000000000..762342934344 --- /dev/null +++ b/test/jdk/jdk/security/JavaDotSecurity/TestLegacyCryptoAlgorithms.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.security.Security; + +/** + * @test + * @bug 8388138 + * @summary Test the default setting of the jdk.crypto.legacyAlgorithms security property + * @comment This property has a default value of "Cipher.RSA/ECB/PKCS1Padding" + * This test assures the default is not changed. + * @run main TestLegacyCryptoAlgorithms + */ +public class TestLegacyCryptoAlgorithms { + + public static void main(String args[]) throws Exception { + String value = Security.getProperty("jdk.crypto.legacyAlgorithms"); + if (value == null || !value.equals("Cipher.RSA/ECB/PKCS1Padding")) { + throw new RuntimeException("Test failed: jdk.crypto.legacyAlgorithms " + + "security property does not have default value of Cipher.RSA/ECB/PKCS1Padding"); + } + } +} From cf0239364b06694c6f61b6ea2b04c2f244954df8 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 27 Aug 2026 19:27:16 +0000 Subject: [PATCH 120/223] 8388795: Add --app-resources CLI option to copy files and directories into the application resources directory Reviewed-by: asemenyuk --- .../internal/LinuxPackageBuilder.java | 1 + .../internal/LinuxPackagingPipeline.java | 3 +- .../internal/MacPackagingPipeline.java | 1 + .../jpackage/internal/ApplicationBuilder.java | 9 + .../internal/ApplicationImageUtils.java | 1 + .../jdk/jpackage/internal/FromOptions.java | 5 + .../internal/cli/StandardHelpFormatter.java | 5 +- .../jpackage/internal/cli/StandardOption.java | 11 + .../jpackage/internal/model/Application.java | 10 + .../internal/model/ApplicationLayout.java | 19 +- .../model/ApplicationLayoutMixin.java | 9 +- .../resources/HelpResources.properties | 25 + src/jdk.jpackage/share/man/jpackage.md | 22 + .../jdk/jpackage/test/ApplicationLayout.java | 11 +- .../jdk/jpackage/test/JPackageCommand.java | 1 + .../jpackage/internal/AppImageFileTest.java | 1 + .../internal/PackagingPipelineTest.java | 4 + .../internal/cli/StandardOptionTest.java | 74 ++- .../jdk/jpackage/internal/cli/help-linux.txt | 8 + .../jdk/jpackage/internal/cli/help-macos.txt | 8 + .../jpackage/internal/cli/help-windows.txt | 8 + .../jpackage/internal/cli/jpackage-options.md | 1 + .../internal/model/ApplicationLayoutTest.java | 3 +- .../tools/jpackage/share/AppContentTest.java | 165 +++--- .../jpackage/share/AppImageFillOrderTest.java | 471 ++++++++++++------ test/jdk/tools/jpackage/share/ErrorTest.java | 3 +- .../tools/jpackage/share/InOutPathTest.java | 1 + 27 files changed, 643 insertions(+), 237 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index cd4d674432ec..1ac3e281ab68 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -134,6 +134,7 @@ private static LinuxApplicationLayout usrTreePackageLayout(Path prefix, String p .desktopIntegrationDirectory(lib) .appModsDirectory(lib.resolve("app/mods")) .contentDirectory(lib) + .resourcesDirectory(lib) .create(), lib.resolve("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java index 4b846db32316..d84c7fcae7fc 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,6 +113,7 @@ private static void writeLauncherIcons( .desktopIntegrationDirectory("lib") .appModsDirectory("lib/app/mods") .contentDirectory("lib") + .resourcesDirectory("lib") .create(); static final LinuxApplicationLayout APPLICATION_LAYOUT = LinuxApplicationLayout.create( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 25d97e155079..d0724648e36b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -667,6 +667,7 @@ public void execute(TaskAction taskAction) throws IOException { .desktopIntegrationDirectory("Contents/Resources") .appModsDirectory("Contents/app/mods") .contentDirectory("Contents") + .resourcesDirectory("Contents/Resources") .create(); static final MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index bb5f1a98a995..cd0ff8d0da2a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -65,6 +65,7 @@ final class ApplicationBuilder { appDirSources = other.appDirSources; externalApp = other.externalApp; contentDirSources = other.contentDirSources; + resourcesDirSources = other.resourcesDirSources; appImageLayout = other.appImageLayout; runtimeBuilder = other.runtimeBuilder; launchers = other.launchers; @@ -96,6 +97,7 @@ Application create() { Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), Optional.ofNullable(appDirSources).orElseGet(List::of), Optional.ofNullable(contentDirSources).orElseGet(List::of), + Optional.ofNullable(resourcesDirSources).orElseGet(List::of), appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, @@ -179,6 +181,11 @@ ApplicationBuilder contentDirSources(Collection v) { return this; } + ApplicationBuilder resourcesDirSources(Collection v) { + resourcesDirSources = v; + return this; + } + ApplicationBuilder derivedVersionNormalizer(UnaryOperator v) { derivedVersionNormalizer = v; return this; @@ -339,6 +346,7 @@ static Application overrideAppImageLayout(Application app, AppImageLayout appIma app.copyright(), app.appDirSources(), app.contentDirSources(), + app.resourcesDirSources(), Objects.requireNonNull(appImageLayout), app.runtimeBuilder(), app.launchers(), @@ -388,6 +396,7 @@ String copyright() { private Collection appDirSources; private ExternalApplication externalApp; private Collection contentDirSources; + private Collection resourcesDirSources; private AppImageLayout appImageLayout; private RuntimeBuilder runtimeBuilder; private ApplicationLaunchers launchers; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index 5edc4d69c813..8a42004da3a5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -85,6 +85,7 @@ static ApplicationImageTaskAction createCopyCont return env -> { for (var e : List.of( Map.entry(env.app().appDirSources(), env.resolvedLayout().appDirectory()), + Map.entry(env.app().resourcesDirSources(), env.resolvedLayout().resourcesDirectory()), Map.entry(env.app().contentDirSources(), env.resolvedLayout().contentDirectory()) )) { RootedPath.copy(e.getKey().stream(), e.getValue(), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java index 4b4e6f9dbac3..f2b2290d9c15 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.cli.StandardOption.ADDITIONAL_LAUNCHERS; import static jdk.jpackage.internal.cli.StandardOption.ADD_MODULES; import static jdk.jpackage.internal.cli.StandardOption.APP_CONTENT; +import static jdk.jpackage.internal.cli.StandardOption.APP_RESOURCES; import static jdk.jpackage.internal.cli.StandardOption.APP_VERSION; import static jdk.jpackage.internal.cli.StandardOption.COPYRIGHT; import static jdk.jpackage.internal.cli.StandardOption.DESCRIPTION; @@ -187,6 +188,10 @@ private static ApplicationBuilder createApplicationBuilder( // from the original list of source files for the given destination file. return v.reversed().stream().flatMap(Collection::stream).toList(); }).ifPresent(appBuilder::contentDirSources); + APP_RESOURCES.findIn(options).map((List> v) -> { + return v.reversed().stream().flatMap(Collection::stream).toList(); + }).ifPresent(appBuilder::resourcesDirSources); + if (isRuntimeInstaller) { appBuilder.appImageLayout(runtimeLayout); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardHelpFormatter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardHelpFormatter.java index d938e6022570..0845b9e765e5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardHelpFormatter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardHelpFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,8 @@ private static Stream> genericOptions() { private static Stream> appImageOptions() { return Stream.of( StandardOption.INPUT, - StandardOption.APP_CONTENT + StandardOption.APP_CONTENT, + StandardOption.APP_RESOURCES ).map(OptionValue::getSpec); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 1cfdf3261105..2fde8ebb3f24 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -222,6 +222,17 @@ public boolean test(Path path) { })) .createArray(toExplodedPathList()); + public static final OptionValue>> APP_RESOURCES = existingPathOption("app-resources") + .tokenizer(pathSeparator()) + .valuePattern("additional resources") + .description("help.option.app-resources" + resourceKeySuffix(OperatingSystem.current())) + .outOfScope(NOT_BUILDING_APP_IMAGE) + .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) + .mutate(createOptionSpecBuilderMutator((b, context) -> { + b.description("help.option.app-resources" + resourceKeySuffix(context.os())); + })) + .createArray(toExplodedPathList()); + static final OptionValue FILE_ASSOCIATIONS_INTERNAL = fileOption("file-associations") .tokenizer(pathSeparator()) .outOfScope(BundlingOperationModifier.BUNDLE_RUNTIME) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 7860a04faacd..3a594e9f6ae4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -100,6 +100,15 @@ public non-sealed interface Application extends BundleSpec { */ Collection contentDirSources(); + /** + * Gets the source paths that should be copied into + * {@link ApplicationLayout#resourcesDirectory()} directory of the image of this + * application. + * + * @return the source paths + */ + Collection resourcesDirSources(); + /** * Gets the unresolved app image layout of this application. * @@ -252,6 +261,7 @@ record Stub( String copyright, Collection appDirSources, Collection contentDirSources, + Collection resourcesDirSources, AppImageLayout imageLayout, Optional runtimeBuilder, List launchers, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 013d2fc78cdd..e0935cec9304 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,6 +100,7 @@ private Builder(ApplicationLayout appLayout) { appModsDirectory = appLayout.appModsDirectory(); desktopIntegrationDirectory = appLayout.desktopIntegrationDirectory(); contentDirectory = appLayout.contentDirectory(); + resourcesDirectory = appLayout.resourcesDirectory(); } public ApplicationLayout create() { @@ -111,11 +112,13 @@ public ApplicationLayout create() { Objects.requireNonNull(appModsDirectory); Objects.requireNonNull(desktopIntegrationDirectory); Objects.requireNonNull(contentDirectory); + Objects.requireNonNull(resourcesDirectory); return ApplicationLayout.create(new AppImageLayout.Stub( rootDirectory, runtimeDirectory), new ApplicationLayoutMixin.Stub( launchersDirectory, appDirectory, appModsDirectory, - desktopIntegrationDirectory, contentDirectory)); + desktopIntegrationDirectory, contentDirectory, + resourcesDirectory)); } public Builder setAll(String path) { @@ -130,6 +133,7 @@ public Builder setAll(Path path) { appModsDirectory(path); desktopIntegrationDirectory(path); contentDirectory(path); + resourcesDirectory(path); return this; } @@ -141,6 +145,7 @@ public Builder mutate(UnaryOperator mapper) { appModsDirectory(mapNullablePath(mapper, appModsDirectory)); desktopIntegrationDirectory(mapNullablePath(mapper, desktopIntegrationDirectory)); contentDirectory(mapNullablePath(mapper, contentDirectory)); + resourcesDirectory(mapNullablePath(mapper, resourcesDirectory)); return this; } @@ -207,6 +212,15 @@ public Builder contentDirectory(Path v) { return this; } + public Builder resourcesDirectory(String v) { + return resourcesDirectory(Path.of(v)); + } + + public Builder resourcesDirectory(Path v) { + resourcesDirectory = v; + return this; + } + private Path rootDirectory = Path.of(""); private Path launchersDirectory; private Path appDirectory; @@ -214,5 +228,6 @@ public Builder contentDirectory(Path v) { private Path appModsDirectory; private Path desktopIntegrationDirectory; private Path contentDirectory; + private Path resourcesDirectory; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java index 10528b7bd6af..9be8b5688c30 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,9 +56,14 @@ public interface ApplicationLayoutMixin { */ Path contentDirectory(); + /** + * Path to directory with additional application resources. + */ + Path resourcesDirectory(); + /** * Default implementation of {@link ApplicationLayoutMixin} interface. */ - record Stub(Path launchersDirectory, Path appDirectory, Path appModsDirectory, Path desktopIntegrationDirectory, Path contentDirectory) implements ApplicationLayoutMixin { + record Stub(Path launchersDirectory, Path appDirectory, Path appModsDirectory, Path desktopIntegrationDirectory, Path contentDirectory, Path resourcesDirectory) implements ApplicationLayoutMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties index 90f4a579bfec..4b058097f23e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties @@ -134,11 +134,15 @@ help.option.add-modules=\ help.option.app-content=\ \ A comma separated list of paths to files and/or directories\n\ \ to add to the application payload.\n\ +\ --app-content is processed after --app-resources, independent\n\ +\ of command-line order.\n\ \ This option can be used more than once. help.option.app-content.mac=\ \ A comma separated list of paths to files and/or directories\n\ \ to add to the application payload.\n\ +\ --app-content is processed after --app-resources, independent\n\ +\ of command-line order.\n\ \ This option can be used more than once.\n\ \ Note: The value should be a directory with the "Resources"\n\ \ subdirectory (or any other directory that is valid in the "Contents"\n\ @@ -146,6 +150,27 @@ help.option.app-content.mac=\ \ invalid application bundle which may fail code signing and/or\n\ \ notarization. +help.option.app-resources.linux=\ +\ A colon-separated list of paths to files and/or directories\n\ +\ to add to the application's "lib" directory.\n\ +\ If a file from --app-resources conflicts with one from\n\ +\ --app-content, the file from --app-content is used.\n\ +\ This option can be used more than once. + +help.option.app-resources.mac=\ +\ A colon-separated list of paths to files and/or directories\n\ +\ to add to the application's "Contents/Resources" directory.\n\ +\ If a file from --app-resources conflicts with one from\n\ +\ --app-content, the file from --app-content is used.\n\ +\ This option can be used more than once. + +help.option.app-resources.win=\ +\ A semicolon-separated list of paths to files and/or directories\n\ +\ to add to the application image root directory.\n\ +\ If a file from --app-resources conflicts with one from\n\ +\ --app-content, the file from --app-content is used.\n\ +\ This option can be used more than once. + help.option.app-image=\ \ Location of the predefined application image that is used\n\ \ to build an installable package\n\ diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md index 3467c53e5955..8b34a56b4f04 100644 --- a/src/jdk.jpackage/share/man/jpackage.md +++ b/src/jdk.jpackage/share/man/jpackage.md @@ -255,6 +255,9 @@ The `jpackage` tool will take as input a Java application and a Java run-time im : A comma separated list of paths to files and/or directories to add to the application payload. + --app-content is processed after --app-resources, independent + of command-line order. + This option can be used more than once. macOS note: The value should be a directory with the "Resources" @@ -263,6 +266,25 @@ The `jpackage` tool will take as input a Java application and a Java run-time im jpackage may produce invalid application bundle which may fail code signing and/or notarization. +`--app-resources` *additional-resources* + +: A list of paths to files and/or directories separated by the + platform-specific path separator (`:` on Linux and macOS; `;` on Windows), + to add to the application resources directory. + + A colliding file from --app-content replaces + one from --app-resources. + + This option can be used more than once. + + Destination: + + - Windows: application image root + + - Linux: application image lib directory + + - macOS: Contents/Resources + ### Options for creating the application launcher(s): diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java index 0701421e999f..0f56d6dbd124 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ public record ApplicationLayout(Path launchersDirectory, Path appDirectory, Path runtimeDirectory, Path runtimeHomeDirectory, Path appModsDirectory, - Path desktopIntegrationDirectory, Path contentDirectory, Path libapplauncher) { + Path desktopIntegrationDirectory, Path contentDirectory, Path resourcesDirectory, + Path libapplauncher) { public ApplicationLayout resolveAt(Path root) { return new ApplicationLayout( @@ -40,6 +41,7 @@ public ApplicationLayout resolveAt(Path root) { resolve(root, appModsDirectory), resolve(root, desktopIntegrationDirectory), resolve(root, contentDirectory), + resolve(root, resourcesDirectory), resolve(root, libapplauncher)); } @@ -52,6 +54,7 @@ public static ApplicationLayout linuxAppImage() { Path.of("lib/app/mods"), Path.of("lib"), Path.of("lib"), + Path.of("lib"), Path.of("lib/libapplauncher.so") ); } @@ -65,6 +68,7 @@ public static ApplicationLayout windowsAppImage() { Path.of("app/mods"), Path.of(""), Path.of(""), + Path.of(""), null ); } @@ -78,6 +82,7 @@ public static ApplicationLayout macAppImage() { Path.of("Contents/app/mods"), Path.of("Contents/Resources"), Path.of("Contents"), + Path.of("Contents/Resources"), null ); } @@ -113,6 +118,7 @@ public static ApplicationLayout platformJavaRuntime() { null, null, null, + null, null ); } @@ -128,6 +134,7 @@ public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, lib.resolve("app/mods"), lib, lib, + lib, lib.resolve("lib/libapplauncher.so") ); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 733a087fe683..eda354079bf4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1508,6 +1508,7 @@ public static enum ReadOnlyPathAssert { return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(cmd)); }).create()), APP_CONTENT(new Builder("--app-content").multiple().create()), + APP_RESOURCES(new Builder("--app-resources").multiple().create()), RESOURCE_DIR(new Builder("--resource-dir").create()), MAC_DMG_CONTENT(new Builder("--mac-dmg-content").multiple().create()), RUNTIME_IMAGE(new Builder("--runtime-image").create()); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 85b15d77052d..30ee8a41255f 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -230,6 +230,7 @@ private Application createApplication() { null, List.of(), List.of(), + List.of(), null, Optional.empty(), new ApplicationLaunchers( diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java index 1db439469f31..23469a46088d 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -223,6 +223,7 @@ void testCreateRuntimeInstaller(boolean transformLayout, @TempDir Path workDir) .runtimeDirectory("runtime") .appModsDirectory("lib") .contentDirectory("lib") + .resourcesDirectory("lib") .desktopIntegrationDirectory("lib") .create(); } else { @@ -618,6 +619,7 @@ private static Application createApp(AppImageLayout appImageLayout, Optional pathOptionsValid() { + return Stream.of( + Arguments.of(StandardOption.APP_CONTENT, ","), + Arguments.of(StandardOption.APP_RESOURCES, File.pathSeparator) + ); + } + + @ParameterizedTest + @CsvSource({ + "app-content,COMMA", + "app-resources,PATH_SEPARATOR", + }) + public void test_AppContent_valid( + @ConvertWith(OptionValueConverter.class) OptionValue>> option, + Delimiter delimiter, @TempDir Path workDir) throws IOException { - var spec = StandardOption.APP_CONTENT.getSpec(); + var spec = option.getSpec(); var contentDir = workDir.resolve("a"); var emptyDir = contentDir.resolve("b/empty-dir"); @@ -228,10 +244,10 @@ public void test_APP_CONTENT_valid(@TempDir Path workDir) throws IOException { Object convertedValue = spec.convert( spec.name(), - StringToken.of(Stream.of(contentDir, file).map(Path::toString).collect(joining(","))) + StringToken.of(Stream.of(contentDir, file).map(Path::toString).collect(joining(delimiter.value))) ).orElseThrow(); - var paths = StandardOption.APP_CONTENT.getFrom(Options.of(Map.of(StandardOption.APP_CONTENT, convertedValue))); + var paths = option.getFrom(Options.of(Map.of(option, convertedValue))); var sortedPathList = paths.stream().flatMap(Collection::stream).map(RootedPath::branch).sorted().toList(); var expectedPathList = Stream.of( @@ -245,9 +261,27 @@ public void test_APP_CONTENT_valid(@TempDir Path workDir) throws IOException { assertEquals(expectedPathList, sortedPathList); } - @Test - public void test_APP_CONTENT_invalid(@TempDir Path workDir) throws IOException { - var spec = StandardOption.APP_CONTENT.getSpec(); + enum Delimiter { + COMMA(","), + PATH_SEPARATOR(File.pathSeparator), + ; + + Delimiter(String value) { + this.value = Objects.requireNonNull(value); + } + + private final String value; + } + + @ParameterizedTest + @CsvSource({ + "app-content", + "app-resources", + }) + public void test_AppContent_invalid( + @ConvertWith(OptionValueConverter.class) OptionValue option, + @TempDir Path workDir) throws IOException { + var spec = option.getSpec(); var token = StringToken.of(workDir.resolve("nonexistent").toString()); var result = spec.convert(spec.name(), token); @@ -951,6 +985,30 @@ private static Set filterByType(Collection ops, Class< ); } + static final class OptionValueConverter extends SimpleArgumentConverter { + + @Override + protected Object convert(Object source, Class targetType) { + if (!OptionValue.class.isAssignableFrom(targetType)) { + throw new IllegalArgumentException(); + } + + if (source == null) { + return null; + } + + if (source instanceof String optionName) { + return Utils.getOptionsWithSpecs(StandardOption.class).filter(op -> { + return op.getOption().spec().names().contains(OptionName.of(optionName)); + }).findFirst().orElseThrow(() -> { + throw new IllegalArgumentException("Failed to find standard option with the name=[" + optionName + "]"); + }); + } else { + throw new IllegalArgumentException(); + } + } + } + private static final Path GOLDEN_JPACKAGE_OPTIONS_MD = TKit.TEST_SRC_ROOT.resolve( "junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md"); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-linux.txt b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-linux.txt index 8cb5b0c17cf8..1068fa962b83 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-linux.txt +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-linux.txt @@ -129,6 +129,14 @@ Options for creating the application image: --app-content [,...] A comma separated list of paths to files and/or directories to add to the application payload. + --app-content is processed after --app-resources, independent + of command-line order. + This option can be used more than once. + --app-resources [:...] + A colon-separated list of paths to files and/or directories + to add to the application's "lib" directory. + If a file from --app-resources conflicts with one from + --app-content, the file from --app-content is used. This option can be used more than once. --input -i Path of the input directory that contains the files to be packaged diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-macos.txt b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-macos.txt index 607012c16b47..91e0e773c8ef 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-macos.txt +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-macos.txt @@ -135,12 +135,20 @@ Options for creating the application image: --app-content [,...] A comma separated list of paths to files and/or directories to add to the application payload. + --app-content is processed after --app-resources, independent + of command-line order. This option can be used more than once. Note: The value should be a directory with the "Resources" subdirectory (or any other directory that is valid in the "Contents" directory of the application bundle). Otherwise, jpackage may produce invalid application bundle which may fail code signing and/or notarization. + --app-resources [:...] + A colon-separated list of paths to files and/or directories + to add to the application's "Contents/Resources" directory. + If a file from --app-resources conflicts with one from + --app-content, the file from --app-content is used. + This option can be used more than once. --input -i Path of the input directory that contains the files to be packaged (absolute path or relative to the current directory) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt index 89c235ac3a35..2b3096964723 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt @@ -129,6 +129,14 @@ Options for creating the application image: --app-content [,...] A comma separated list of paths to files and/or directories to add to the application payload. + --app-content is processed after --app-resources, independent + of command-line order. + This option can be used more than once. + --app-resources [;...] + A semicolon-separated list of paths to files and/or directories + to add to the application image root directory. + If a file from --app-resources conflicts with one from + --app-content, the file from --app-content is used. This option can be used more than once. --input -i Path of the input directory that contains the files to be packaged diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md index 59ae0d176c1e..2fac870b4895 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md @@ -5,6 +5,7 @@ | --add-modules | bundle | | | | CONCATENATE | | --app-content | bundle | | | | CONCATENATE | | --app-image | mac-sign, native-bundle | | x | | USE_LAST | +| --app-resources | bundle | | | | CONCATENATE | | --app-version | bundle | x | x | | USE_LAST | | --arguments | bundle | | | x | CONCATENATE | | --copyright | bundle | x | x | | USE_LAST | diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 063b11ec5895..ce4ebd1ab130 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,7 @@ public static ApplicationLayout createLayout() { .runtimeDirectory("runtime") .appModsDirectory("mods") .contentDirectory("content") + .resourcesDirectory("resources") .desktopIntegrationDirectory("lib/apps") .create(); } diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 66b7aaa421cd..063322e045e6 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -28,6 +28,7 @@ import static jdk.internal.util.OperatingSystem.WINDOWS; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -53,6 +54,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.FailedCommandErrorValidator; @@ -66,17 +68,17 @@ /** - * Tests generation of packages with additional content in app image. + * Tests generation of packages with additional content or resources in app image. */ /* * @test - * @summary jpackage with --app-content option + * @summary jpackage with --app-content or --app-resources option * @library /test/jdk/tools/jpackage/helpers * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @build AppContentTest - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppContentTest */ public class AppContentTest { @@ -176,8 +178,14 @@ List expectedWarnings() { private Path appContent; } + private static Collection withOptions(Stream specs) { + return specs.flatMap(builder -> Stream.of(AppFilesOption.values()) + .map(option -> new Object[] { builder.create(option) })) + .toList(); + } + public static Collection test() { - return Stream.of( + var tests = Stream.of( build().add(TEST_JAVA).add(TEST_DUKE), build().add(TEST_JAVA).add(TEST_BAD), build().startGroup().add(TEST_JAVA).add(TEST_DUKE).endGroup().add(TEST_DIR), @@ -193,39 +201,100 @@ public static Collection test() { build().add(createTextFileContent("a/b/c/d", "Foo")).add(createTextFileContent("a", "Bar")), // Same name: one is a file, another is a directory. build().add(createTextFileContent("a", "Bar")).add(createTextFileContent("a/b/c/d", "Foo")) - ).map(TestSpec.Builder::create).map(v -> { - return new Object[] {v}; - }).toList(); + ); + + return withOptions(tests); } public static Collection testAppImage() { - return Stream.of( + var tests = Stream.of( build().add(NonExistentPath.create("*output-app-image*", JPackageCommand::outputBundle)) - ).map(TestSpec.Builder::create).map(v -> { - return new Object[] {v}; - }).toList(); + ); + + return withOptions(tests); } public static Collection testSymlink() { - return Stream.of( + var tests = Stream.of( build().add(TEST_JAVA) .add(new SymlinkContentFactory("Links", "duke-link", "duke-target")) .add(new SymlinkContentFactory("", "a/b/foo-link", "c/bar-target")) - ).map(TestSpec.Builder::create).map(v -> { - return new Object[] {v}; - }).toList(); + ); + + return withOptions(tests); + } + + private enum AppFilesOption { + CONTENT("--app-content", ",", ApplicationLayout::contentDirectory, TKit.isOSX()), + RESOURCES("--app-resources", File.pathSeparator, + ApplicationLayout::resourcesDirectory, false); + + AppFilesOption(String optionName, String delimiter, + Function outputRoot, + boolean wrapInResourcesOnMac) { + this.optionName = optionName; + this.delimiter = delimiter; + this.outputRoot = outputRoot; + this.wrapInResourcesOnMac = wrapInResourcesOnMac; + } + + Path optionPath(Path path) { + if (wrapInResourcesOnMac() + && Optional.ofNullable(path.getParent()) + .map(Path::getFileName) + .map(RESOURCES_DIR::equals) + .orElse(false)) { + return path.getParent(); + } + return path; + } + + Path outputRoot(JPackageCommand cmd) { + var root = outputRoot.apply(cmd.appLayout()); + return wrapInResourcesOnMac + ? root.resolve(RESOURCES_DIR) + : root; + } + + String optionName() { + return optionName; + } + + boolean wrapInResourcesOnMac() { + return wrapInResourcesOnMac; + } + + private final String optionName; + private final String delimiter; + private final Function outputRoot; + // On OSX `--app-content` paths will be copied into the "Contents" folder + // of the output app image. + // "codesign" imposes restrictions on the directory structure of "Contents" folder. + // In particular, random files should be placed in "Contents/Resources" folder + // otherwise "codesign" will fail to sign. + // Need to prepare arguments for `--app-content` accordingly. + private final boolean wrapInResourcesOnMac; } - public record TestSpec(List> contentFactories) { + private record TestSpec(AppFilesOption option, + List> contentFactories) { public TestSpec { + Objects.requireNonNull(option); contentFactories.stream().flatMap(List::stream).forEach(Objects::requireNonNull); + if (contentFactories.isEmpty()) { + throw new IllegalArgumentException(); + } } @Override public String toString() { - return contentFactories.stream().map(group -> { + var sb = new StringBuilder(); + + sb.append(option).append(" ").append(contentFactories.stream().map(group -> { return group.stream().map(ContentFactory::toString).collect(joining(",")); - }).collect(joining("; ")); + }).collect(joining("; "))); + + return sb.toString(); } void test(ConfigurationTarget target) { @@ -242,26 +311,17 @@ void test(ConfigurationTarget target) { .addInitializer(cmd -> { contentFactories.stream().map(group -> { return group.stream().map(contentFactory -> { - return contentFactory.create(cmd); + return contentFactory.create(cmd, option.wrapInResourcesOnMac()); }).toList(); }).forEach(allContent::add); }).addInitializer(cmd -> { allContent.stream().map(group -> { - return Stream.of("--app-content", group.stream() + return Stream.of(option.optionName, group.stream() .map(Content::paths) .flatMap(List::stream) - .map(appContentArg -> { - if (COPY_IN_RESOURCES && Optional.ofNullable(appContentArg.getParent()) - .map(Path::getFileName) - .map(RESOURCES_DIR::equals) - .orElse(false)) { - return appContentArg.getParent(); - } else { - return appContentArg; - } - }) + .map(path -> option.optionPath(path)) .map(Path::toString) - .collect(joining(","))); + .collect(joining(option.delimiter))); }).flatMap(x -> x).forEachOrdered(cmd::addArgument); }); @@ -278,7 +338,7 @@ void test(ConfigurationTarget target) { return; } - var appContentRoot = getAppContentRoot(cmd); + var appContentRoot = option.outputRoot(cmd); Set disabledVerifiers = new HashSet<>(); @@ -329,8 +389,8 @@ void test(ConfigurationTarget target) { } static final class Builder { - TestSpec create() { - return new TestSpec(groups); + TestSpec create(AppFilesOption option) { + return new TestSpec(option, groups); } final class GroupBuilder { @@ -386,17 +446,8 @@ private static TestSpec.Builder build() { return new TestSpec.Builder(); } - private static Path getAppContentRoot(JPackageCommand cmd) { - final Path contentDir = cmd.appLayout().contentDirectory(); - if (COPY_IN_RESOURCES) { - return contentDir.resolve(RESOURCES_DIR); - } else { - return contentDir; - } - } - - private static Path createAppContentRoot() { - if (COPY_IN_RESOURCES) { + private static Path createAppContentRoot(boolean srcRootMustBeResourcesDir) { + if (srcRootMustBeResourcesDir) { return TKit.createTempDirectory("app-content").resolve(RESOURCES_DIR); } else { return TKit.createTempDirectory("app-content"); @@ -415,7 +466,7 @@ private static boolean isDirectoryEmpty(Path path) throws IOException { @FunctionalInterface private interface ContentFactory { - Content create(JPackageCommand cmd); + Content create(JPackageCommand cmd, boolean srcRootMustBeResourcesDir); } private interface Content { @@ -556,7 +607,7 @@ private NonExistentPath(String label, Function makePath) } @Override - public Content create(JPackageCommand cmd) { + public Content create(JPackageCommand cmd, boolean srcRootMustBeResourcesDir) { var nonexistent = makePath.apply(cmd); if (Files.exists(nonexistent)) { throw new IllegalStateException(); @@ -669,8 +720,8 @@ private record SymlinkContentFactory(Path basedir, Path symlink, Path symlinked) } @Override - public Content create(JPackageCommand cmd) { - final var appContentRoot = createAppContentRoot(); + public Content create(JPackageCommand cmd, boolean srcRootMustBeResourcesDir) { + final var appContentRoot = createAppContentRoot(srcRootMustBeResourcesDir); final var symlinkPath = appContentRoot.resolve(symlinkPath()); final var symlinkedPath = appContentRoot.resolve(symlinkedPath()); @@ -686,7 +737,7 @@ public Content create(JPackageCommand cmd) { } List contentPaths; - if (COPY_IN_RESOURCES) { + if (srcRootMustBeResourcesDir) { contentPaths = List.of(appContentRoot); } else if (basedir.equals(Path.of(""))) { contentPaths = Stream.of(symlinkPath(), symlinkedPath()).map(path -> { @@ -743,17 +794,17 @@ private static final class FileContentFactory implements ContentFactory { } @Override - public Content create(JPackageCommand cmd) { + public Content create(JPackageCommand cmd, boolean srcRootMustBeResourcesDir) { Path srcPath = factory.get(); if (!srcPath.endsWith(pathInAppContentRoot)) { throw new IllegalArgumentException(); } Path dstPath; - if (!COPY_IN_RESOURCES) { + if (!srcRootMustBeResourcesDir) { dstPath = srcPath; } else { - var contentDir = createAppContentRoot(); + var contentDir = createAppContentRoot(srcRootMustBeResourcesDir); dstPath = contentDir.resolve(pathInAppContentRoot); try { FileUtils.copyRecursive(srcPath, dstPath); @@ -778,13 +829,5 @@ public String toString() { private static final ContentFactory TEST_DIR = createDirTreeContent("apps"); private static final ContentFactory TEST_BAD = NonExistentPath.create("non-existent"); - // On OSX `--app-content` paths will be copied into the "Contents" folder - // of the output app image. - // "codesign" imposes restrictions on the directory structure of "Contents" folder. - // In particular, random files should be placed in "Contents/Resources" folder - // otherwise "codesign" will fail to sign. - // Need to prepare arguments for `--app-content` accordingly. - private static final boolean COPY_IN_RESOURCES = TKit.isOSX(); - private static final Path RESOURCES_DIR = Path.of("Resources"); } diff --git a/test/jdk/tools/jpackage/share/AppImageFillOrderTest.java b/test/jdk/tools/jpackage/share/AppImageFillOrderTest.java index 75c0ddfc16f1..309291f73166 100644 --- a/test/jdk/tools/jpackage/share/AppImageFillOrderTest.java +++ b/test/jdk/tools/jpackage/share/AppImageFillOrderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,33 +21,37 @@ * questions. */ -import static java.util.stream.Collectors.toMap; - import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.TreeMap; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.util.Slot; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.RunnablePackageTest.Action; import jdk.jpackage.test.TKit; /* * @test * @summary test order in which jpackage fills app image * @library /test/jdk/tools/jpackage/helpers + * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AppImageFillOrderTest.java * @run main/othervm/timeout=1440 -Xmx512m @@ -63,6 +67,7 @@ * Custom content comes from: *

    *
  • input directory (--input) + *
  • app resources (--app-resources) *
  • app content (--app-content) *
      */ @@ -70,8 +75,14 @@ public class AppImageFillOrderTest { @Test @ParameterSupplier - public void test(AppImageOverlay overlays[]) { - test(createJPackage().setFakeRuntime(), overlays); + public void test(AppImageOverlay overlay) { + test(initJPackage().andThen(JPackageCommand::setFakeRuntime), false, overlay); + } + + @Test + @ParameterSupplier("test") + public void testAppImage(AppImageOverlay overlay) { + test(initJPackage().andThen(JPackageCommand::setFakeRuntime), true, overlay); } /** @@ -79,27 +90,31 @@ public void test(AppImageOverlay overlays[]) { * @param jlink */ @Test - @Parameter("true") - @Parameter("false") - public void testRuntime(boolean jlink) { - var cmd = createJPackage(); - if (jlink) { - cmd.ignoreDefaultRuntime(true); - } else { - // Configure fake runtime and create it. - cmd.setFakeRuntime().executePrerequisiteActions(); - - var runtimeDir = Path.of(cmd.getArgumentValue("--runtime-image")); - if (!runtimeDir.toAbsolutePath().normalize().startsWith(TKit.workDir().toAbsolutePath().normalize())) { - throw new IllegalStateException(String.format( - "Fake runtime [%s] created outside of the test work directory [%s]", - runtimeDir, TKit.workDir())); - } + @Parameter({"true", "true"}) + @Parameter({"true", "false"}) + @Parameter({"false", "true"}) + @Parameter({"false", "false"}) + public void testRuntime(boolean appImage, boolean jlink) { + + Consumer initializer = cmd -> { + if (jlink) { + cmd.ignoreDefaultRuntime(true); + } else { + // Configure fake runtime and create it. + cmd.setFakeRuntime().executePrerequisiteActions(); + + var runtimeDir = Path.of(cmd.getArgumentValue("--runtime-image")); + if (!runtimeDir.toAbsolutePath().normalize().startsWith(TKit.workDir().toAbsolutePath().normalize())) { + throw new IllegalStateException(String.format( + "Fake runtime [%s] created outside of the test work directory [%s]", + runtimeDir, TKit.workDir())); + } - TKit.createTextFile(runtimeDir.resolve(RUNTIME_RELEASE_FILE), List.of("Foo release")); - } + TKit.createTextFile(runtimeDir.resolve(RUNTIME_RELEASE_FILE), List.of("Foo release")); + } + }; - test(cmd, AppImageAppContentOverlay.APP_CONTENT_RUNTIME_RELEASE_FILE); + test(initJPackage().andThen(initializer), appImage, StandardAppImageOverlay.APP_CONTENT_RUNTIME_RELEASE_FILE); } /** @@ -115,7 +130,7 @@ public void testAppImageFile() throws IOException { buildOverlay(cmd, TKit.createTempDirectory("app-content"), AppImageFile.getPathInAppImage(outputBundle)) .textContent("This is not a valid XML content") - .configureCmdOptions().createOverlayFile(); + .addAppContentOption().createOverlayFile(); // Run jpackage and verify it created valid .jpackage.xml file ignoring the overlay. cmd.executeAndAssertImageCreated(); @@ -124,234 +139,376 @@ public void testAppImageFile() throws IOException { AppImageFile.load(outputBundle); } - private static void test(JPackageCommand cmd, AppImageOverlay... overlays) { - if (overlays.length == 0) { - throw new IllegalArgumentException(); - } + private static void test(Consumer initializer, boolean appImage, AppImageOverlay overlay) { + Objects.requireNonNull(overlay); - final var outputDir = Path.of(cmd.getArgumentValue("--dest")); - final var noOverlaysOutputDir = Path.of(outputDir.toString() + "-no-overlay"); - cmd.setArgumentValue("--dest", noOverlaysOutputDir); - - // Run the command without overlays with redirected output directory. - cmd.execute(); - - final Optional appContentRoot; - if (Stream.of(overlays).anyMatch(AppImageAppContentOverlay.class::isInstance)) { - appContentRoot = Optional.of(TKit.createTempDirectory("app-content")); + final ConfigurationTarget targetWithoutOverlays; + if (appImage) { + targetWithoutOverlays = new ConfigurationTarget(JPackageCommand.helloAppImage()); } else { - appContentRoot = Optional.empty(); + targetWithoutOverlays = new ConfigurationTarget(new PackageTest().configureHelloApp()); } - // Apply overlays to the command. - var fileCopies = Stream.of(overlays).map(overlay -> { - switch (overlay) { - case AppImageDefaultOverlay v -> { - return v.addOverlay(cmd); - } - case AppImageAppContentOverlay v -> { - return v.addOverlay(cmd, appContentRoot.orElseThrow()); - } + targetWithoutOverlays + .addInitializer(initializer) + .addInitializer(cmdWithoutOverlays -> { + cmdWithoutOverlays.setArgumentValue("--dest", cmdWithoutOverlays.getArgumentValue("--dest") + "-no-overlay"); + }) + .apply(JPackageCommand::execute, _ -> {}) + .addInstallVerifier(cmdWithoutOverlays -> { + final ConfigurationTarget target; + if (appImage) { + target = new ConfigurationTarget(new JPackageCommand()); + } else { + target = new ConfigurationTarget(new PackageTest().forTypes(cmdWithoutOverlays.packageType())); } - }).flatMap(Collection::stream).collect(toMap(FileCopy::out, x -> x, (a, b) -> { - return b; - }, TreeMap::new)).values().stream().toList(); - - // Collect paths in the app image that will be affected by overlays. - var noOverlayOutputPaths = fileCopies.stream().map(FileCopy::out).toList(); - - fileCopies = fileCopies.stream().map(v -> { - return new FileCopy(v.in(), outputDir.resolve(noOverlaysOutputDir.relativize(v.out()))); - }).toList(); - // Restore the original output directory for the command and execute it. - cmd.setArgumentValue("--dest", outputDir).execute(); - - for (var i = 0; i != fileCopies.size(); i++) { - var noOverlayPath = noOverlayOutputPaths.get(i); - var fc = fileCopies.get(i); - TKit.assertSameFileContent(fc.in(), fc.out()); - TKit.assertMismatchFileContent(noOverlayPath, fc.out()); - } + Slot> fileCopies = Slot.createEmpty(); + + target.addInitializer(cmd -> { + cmd.clearArguments() + .addArguments(cmdWithoutOverlays.getAllArguments()) + .setDefaultInputOutput() + .setArgumentValue("--input", cmdWithoutOverlays.inputDir()); + + // Apply overlays to the command. + fileCopies.set(overlay.addOverlay(cmd).stream() + .sorted(Comparator.comparing(FileCopy::out).thenComparing(Comparator.comparing(FileCopy::in))) + .toList()); + }) + .apply(JPackageCommand::execute, _ -> {}) + .addInstallVerifier(cmd -> { + + Function unpackRoot = c -> { + return c.isImagePackageType() ? c.outputBundle() : c.pathToUnpackedPackageFile(c.appInstallationDirectory()); + }; + + for (var fc : fileCopies.get()) { + var noOverlayPath = unpackRoot.apply(cmdWithoutOverlays).resolve(fc.out()); + var overlayPath = unpackRoot.apply(cmd).resolve(fc.out()); + TKit.assertSameFileContent(fc.in(), overlayPath); + if (Files.exists(noOverlayPath)) { + TKit.assertMismatchFileContent(noOverlayPath, overlayPath); + } + } + }).test().ifPresent(test -> { + test.run(Action.CREATE_AND_UNPACK); + }); + }).test().ifPresent(test -> { + test.run(Action.CREATE_AND_UNPACK); + }); } public static Collection test() { - return Stream.of( + + var testCases = new ArrayList(); + + Stream.of( // Overwrite main launcher .cfg file from the input dir. - List.of(AppImageDefaultOverlay.INPUT_MAIN_LAUNCHER_CFG), + StandardAppImageOverlay.INPUT_MAIN_LAUNCHER_CFG, // Overwrite main launcher .cfg file from the app content dir. - List.of(AppImageAppContentOverlay.APP_CONTENT_MAIN_LAUNCHER_CFG), + StandardAppImageOverlay.APP_CONTENT_MAIN_LAUNCHER_CFG, // Overwrite main launcher .cfg file from the input dir and from the app content dir. // The one from app content should win. - List.of( - AppImageDefaultOverlay.INPUT_MAIN_LAUNCHER_CFG, - AppImageAppContentOverlay.APP_CONTENT_MAIN_LAUNCHER_CFG - ), + AppImageOverlay.group().overlays( + StandardAppImageOverlay.INPUT_MAIN_LAUNCHER_CFG, + StandardAppImageOverlay.APP_CONTENT_MAIN_LAUNCHER_CFG + ).last().create(), // Overwrite main jar from the app content dir. - List.of(AppImageAppContentOverlay.APP_CONTENT_MAIN_JAR) - ).map(args -> { - return args.toArray(AppImageOverlay[]::new); - }).map(args -> { + StandardAppImageOverlay.APP_CONTENT_MAIN_JAR, + + // The same file is copied from the --app-resources and --app-content options. + // The one from the - app-content should win regardless of the order of the options on the command line. + AppImageOverlay.group().overlays( + StandardAppImageOverlay.APP_RESOURCES_USER_FILE, + StandardAppImageOverlay.APP_CONTENT_USER_FILE).last().create(), + AppImageOverlay.group().overlays( + StandardAppImageOverlay.APP_CONTENT_USER_FILE, + StandardAppImageOverlay.APP_RESOURCES_USER_FILE).first().create() + + ).forEach(testCases::add); + + return testCases.stream().map(args -> { return new Object[] {args}; }).toList(); } - public sealed interface AppImageOverlay { - } - + @FunctionalInterface + public interface AppImageOverlay { - private enum AppImageDefaultOverlay implements AppImageOverlay { - INPUT_MAIN_LAUNCHER_CFG(AppImageFillOrderTest::replaceMainLauncherCfgFile), - ; + Collection addOverlay(JPackageCommand cmd); - AppImageDefaultOverlay(Function func) { - Objects.requireNonNull(func); - this.func = cmd -> { - return List.of(func.apply(cmd)); + static AppImageOverlay fileOverlay(BiFunction initializer) { + Objects.requireNonNull(initializer); + return cmd -> { + return List.of(initializer.apply(cmd, TKit.createTempDirectory("content")).createOverlayFile()); }; } - Collection addOverlay(JPackageCommand cmd) { - return func.apply(cmd); + static GroupAppImageOverlay.Builder group() { + return new GroupAppImageOverlay.Builder(); } - - private final Function> func; } - private enum AppImageAppContentOverlay implements AppImageOverlay { + private enum StandardAppImageOverlay implements AppImageOverlay { + + // Replace the standard main launcher .cfg file with the custom one from the input dir. + INPUT_MAIN_LAUNCHER_CFG(cmd -> { + + final var outputFile = relativize(cmd, cmd.appLauncherCfgPath(null)); + + final var inputDir = Path.of(cmd.getArgumentValue("--input")); + + final var file = inputDir.resolve(outputFile.getFileName()); + + TKit.createTextFile(file, List.of("Hello!")); + + return List.of(new FileCopy(file, outputFile)); + }), + // Replace the standard main launcher .cfg file with the custom one from the app content. - APP_CONTENT_MAIN_LAUNCHER_CFG((cmd, appContentRoot) -> { - return buildOverlay(cmd, appContentRoot, cmd.appLauncherCfgPath(null)) + APP_CONTENT_MAIN_LAUNCHER_CFG(AppImageOverlay.fileOverlay((cmd, contentRoot) -> { + return buildOverlay(cmd, contentRoot, cmd.appLauncherCfgPath(null)) .textContent("!Olleh") - .configureCmdOptions().createOverlayFile(); - }), + .addAppContentOption(); + })), // Replace the jar file that jpackage will pick up from the input directory with the custom one. - APP_CONTENT_MAIN_JAR((cmd, appContentRoot) -> { - return buildOverlay(cmd, appContentRoot, cmd.appLayout().appDirectory().resolve(cmd.getArgumentValue("--main-jar"))) + APP_CONTENT_MAIN_JAR(AppImageOverlay.fileOverlay((cmd, contentRoot) -> { + return buildOverlay(cmd, contentRoot, cmd.appLayout().appDirectory().resolve(cmd.getArgumentValue("--main-jar"))) .textContent("Surprise!") - .configureCmdOptions().createOverlayFile(); - }), + .addAppContentOption(); + })), // Replace "release" file in the runtime directory. - APP_CONTENT_RUNTIME_RELEASE_FILE((cmd, appContentRoot) -> { - return buildOverlay(cmd, appContentRoot, cmd.appLayout().runtimeHomeDirectory().resolve("release")) + APP_CONTENT_RUNTIME_RELEASE_FILE(AppImageOverlay.fileOverlay((cmd, contentRoot) -> { + return buildOverlay(cmd, contentRoot, cmd.appLayout().runtimeHomeDirectory().resolve("release")) .textContent("blob") - .configureCmdOptions().createOverlayFile(); - }), + .addAppContentOption(); + })), + + // "a/b/c.txt" file in the content directory. + APP_CONTENT_USER_FILE(AppImageOverlay.fileOverlay((cmd, contentRoot) -> { + var dstDir = TKit.isOSX() ? cmd.appLayout().resourcesDirectory() : cmd.appLayout().contentDirectory(); + return buildOverlay(cmd, contentRoot, dstDir.resolve("a/b/c.txt")) + .textContent("MACOS_APP_CONTENT_USER_FILE") + .addAppContentOption(); + })), + + // "a/b/c.txt" file in the resources directory. + APP_RESOURCES_USER_FILE(AppImageOverlay.fileOverlay((cmd, contentRoot) -> { + return buildOverlay(cmd, contentRoot, cmd.appLayout().resourcesDirectory().resolve("a/b/c.txt")) + .textContent("APP_RESOURCES_USER_FILE") + .addAppResourcesOption(); + })), + ; - AppImageAppContentOverlay(BiFunction func) { - Objects.requireNonNull(func); - this.func = (cmd, appContentRoot) -> { - return List.of(func.apply(cmd, appContentRoot)); - }; + StandardAppImageOverlay(AppImageOverlay impl) { + this.impl = Objects.requireNonNull(impl); } - Collection addOverlay(JPackageCommand cmd, Path appContentRoot) { - return func.apply(cmd, appContentRoot); + @Override + public Collection addOverlay(JPackageCommand cmd) { + return impl.addOverlay(cmd); } - private final BiFunction> func; + private final AppImageOverlay impl; } - private record FileCopy(Path in, Path out) { - FileCopy { - Objects.requireNonNull(in); - Objects.requireNonNull(out); + private record GroupAppImageOverlay(List group, Selector selector) implements AppImageOverlay { + + GroupAppImageOverlay { + Objects.requireNonNull(selector); + group.forEach(Objects::requireNonNull); + if (group.size() < 2) { + throw new IllegalArgumentException(); + } } - } + enum Selector { + LAST, + FIRST, + EACH, + ; + } - private static FileCopy replaceMainLauncherCfgFile(JPackageCommand cmd) { - // Replace the standard main launcher .cfg file with the custom one from the input dir. - final var outputFile = cmd.appLauncherCfgPath(null); + @Override + public Collection addOverlay(JPackageCommand cmd) { + var fileCopies = group.stream().flatMap(overlay -> { + return overlay.addOverlay(cmd).stream(); + }).toList(); - final var inputDir = Path.of(cmd.getArgumentValue("--input")); + return switch (selector) { + case EACH -> fileCopies; + case FIRST -> List.of(fileCopies.getFirst()); + case LAST -> List.of(fileCopies.getLast()); + }; + } - final var file = inputDir.resolve(outputFile.getFileName()); + @Override + public String toString() { + if (selector == Selector.EACH) { + return String.format("%s", group); + } else { + return String.format("%s%s", selector, group); + } + } - TKit.createTextFile(file, List.of("Hello!")); + final static class Builder { - return new FileCopy(file, outputFile); - } + Builder selector(Selector v) { + selector = v; + return this; + } - private static AppContentOverlayFileBuilder buildOverlay(JPackageCommand cmd, Path appContentRoot, Path outputFile) { - return new AppContentOverlayFileBuilder(cmd, appContentRoot, outputFile); - } + Builder first() { + return selector(Selector.FIRST); + } + Builder last() { + return selector(Selector.LAST); + } - private static final class AppContentOverlayFileBuilder { + Builder overlays(Collection v) { + overlays.addAll(v); + return this; + } - AppContentOverlayFileBuilder(JPackageCommand cmd, Path appContentRoot, Path outputFile) { - if (outputFile.isAbsolute()) { - throw new IllegalArgumentException(); + Builder overlays(AppImageOverlay... v) { + return overlays(List.of(v)); } - if (!outputFile.startsWith(cmd.outputBundle())) { - throw new IllegalArgumentException(); + AppImageOverlay create() { + if (overlays.size() == 1) { + return overlays.getFirst(); + } else { + return new GroupAppImageOverlay( + List.copyOf(overlays), Optional.ofNullable(selector).orElse(Selector.EACH)); + } } + private Selector selector; + private List overlays = new ArrayList<>(); + } + } + + + private record FileCopy(Path in, Path out) { + FileCopy { + Objects.requireNonNull(in); + Objects.requireNonNull(out); + } + } + + + private static OverlayFileBuilder buildOverlay(JPackageCommand cmd, Path appContentRoot, Path outputFile) { + return new OverlayFileBuilder(cmd, appContentRoot, outputFile); + } + + + private static final class OverlayFileBuilder { + + OverlayFileBuilder(JPackageCommand cmd, Path srcRoot, Path outputFile) { this.cmd = Objects.requireNonNull(cmd); - this.outputFile = Objects.requireNonNull(outputFile); - this.appContentRoot = Objects.requireNonNull(appContentRoot); + this.outputFilePathInAppImage = relativize(cmd, outputFile); + this.srcRoot = Objects.requireNonNull(srcRoot); } FileCopy createOverlayFile() { - final var file = appContentRoot.resolve(pathInAppContentDirectory()); + if (srcFile == null) { + throw new IllegalStateException(); + } try { - Files.createDirectories(file.getParent()); + Files.createDirectories(srcFile.getParent()); } catch (IOException ex) { throw new UncheckedIOException(ex); } - fileContentInitializer.accept(file); + fileContentInitializer.accept(srcFile); - return new FileCopy(file, outputFile); + return new FileCopy(srcFile, outputFilePathInAppImage); } - AppContentOverlayFileBuilder configureCmdOptions() { - cmd.addArguments("--app-content", appContentRoot.resolve(pathInAppContentDirectory().getName(0))); + OverlayFileBuilder addAppContentOption() { + addJPackageOption("--app-content", APP_IMAGE_LAYOUT.contentDirectory()); return this; } - AppContentOverlayFileBuilder content(Consumer v) { + OverlayFileBuilder addAppResourcesOption() { + addJPackageOption("--app-resources", APP_IMAGE_LAYOUT.resourcesDirectory()); + return this; + } + + OverlayFileBuilder content(Consumer v) { fileContentInitializer = v; return this; } - AppContentOverlayFileBuilder textContent(String... lines) { + OverlayFileBuilder textContent(String... lines) { return content(path -> { TKit.createTextFile(path, List.of(lines)); }); } - private Path pathInAppContentDirectory() { - return APP_IMAGE_LAYOUT.resolveAt(cmd.outputBundle()).contentDirectory().relativize(outputFile); + private void addJPackageOption(String optionName, Path outputDirectoryInAppImage) { + Objects.requireNonNull(optionName); + + var relativeSrcFilePath = relativize(outputDirectoryInAppImage, outputFilePathInAppImage); + + cmd.addArguments(optionName, srcRoot.resolve(relativeSrcFilePath.getName(0))); + + srcFile = srcRoot.resolve(relativeSrcFilePath); } private Consumer fileContentInitializer; private final JPackageCommand cmd; - private final Path outputFile; - private final Path appContentRoot; + private final Path outputFilePathInAppImage; + private final Path srcRoot; + private Path srcFile; } - private static JPackageCommand createJPackage() { - // With short name. - var cmd = JPackageCommand.helloAppImage().setArgumentValue("--name", "Foo"); + private static Path relativize(Path base, Path path) { + if (base.isAbsolute() != path.isAbsolute()) { + throw new IllegalArgumentException(); + } + + if (base.equals(Path.of(""))) { + return path; + } - // Clean leftovers in the input dir from the previous test run if any. - TKit.deleteDirectoryContentsRecursive(cmd.inputDir()); + if (!path.startsWith(base)) { + throw new IllegalArgumentException(); + } + + return base.relativize(path); + } - return cmd; + private static Path relativize(JPackageCommand cmd, Path path) { + var base = cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory(); + return relativize(base, path); + } + + private static Consumer initJPackage() { + return cmd -> { + // With short name. + cmd.setArgumentValue("--name", "Foo"); + + // Fresh input dir. + cmd.setInputToEmptyDirectory(); + }; + } + + private static JPackageCommand createJPackage() { + return JPackageCommand.helloAppImage().mutate(initJPackage()); } private static final ApplicationLayout APP_IMAGE_LAYOUT = ApplicationLayout.platformAppImage(); diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index a370b755dc4e..77d4de40c1a4 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -658,7 +658,8 @@ public static Collection testRuntimeInstallerInvalidOptions() { List.of("--arguments", "foo"), List.of("--java-options", "-Dfoo.bar=10"), List.of("--add-launcher", "foo=foo.properties"), - List.of("--app-content", "dir")); + List.of("--app-content", "dir"), + List.of("--app-resources", "dir")); if (TKit.isWindows()) { argsStream = Stream.concat(argsStream, Stream.of(List.of("--win-console"))); diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index a9fa48dc1c6c..b6422022fd96 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -73,6 +73,7 @@ public static Collection input() { }, "--dest and --temp in --input")}, })); data.addAll(additionalContentInput(packageTypeAlias, "--app-content")); + data.addAll(additionalContentInput(packageTypeAlias, "--app-resources")); } return data; From ee2ebf6bd75bac05f4446a2cacd0a2f5e7d9c45c Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Thu, 27 Aug 2026 21:01:38 +0000 Subject: [PATCH 121/223] 8386092: Implement JEP 541: Deprecate the macOS/x64 Port for Removal Reviewed-by: dholmes, erikj, shade, jwaters --- .github/workflows/main.yml | 2 +- make/autoconf/platform.m4 | 14 +++++++++++++- make/conf/jib-profiles.js | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 57f81f7fd51e..6151bef13d9c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,7 +60,7 @@ jobs: runs-on: ubuntu-24.04 env: # List of platforms to exclude by default - EXCLUDED_PLATFORMS: 'alpine-linux-x64' + EXCLUDED_PLATFORMS: 'alpine-linux-x64,macos-x64' outputs: linux-x64: ${{ steps.include.outputs.linux-x64 }} linux-x64-variants: ${{ steps.include.outputs.linux-x64-variants }} diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 index 28aea489f7ec..cdeae97c8ac8 100644 --- a/make/autoconf/platform.m4 +++ b/make/autoconf/platform.m4 @@ -660,7 +660,19 @@ AC_DEFUN([PLATFORM_CHECK_DEPRECATION], [ AC_ARG_ENABLE(deprecated-ports, [AS_HELP_STRING([--enable-deprecated-ports@<:@=yes/no@:>@], [Suppress the error when configuring for a deprecated port @<:@no@:>@])]) - # There are no deprecated ports. Implement the deprecation warnings here. + if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + # Unfortunately, variants have not been parsed yet, so we have to check the configure option + # directly. Allow only the directly specified Zero variant, treat any other mix as containing + # something non-Zero. + if test "x$with_jvm_variants" != xzero; then + if test "x$enable_deprecated_ports" = "xyes"; then + AC_MSG_WARN([The macOS/x64 port is deprecated and may be removed in a future release.]) + else + AC_MSG_ERROR(m4_normalize([The macOS/x64 port is deprecated and may be removed in a future release. + Use --enable-deprecated-ports to suppress this error.])) + fi + fi + fi ]) AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION], diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index c7f9fa87a51e..b83ca709a888 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -416,6 +416,7 @@ var getJibProfilesProfiles = function (input, common, data) { "--with-zlib=system", "--with-macosx-version-max=11.00.00", "--enable-compatible-cds-alignment", + "--enable-deprecated-ports", // Use system SetFile instead of the one in the devkit as the // devkit one may not work on Catalina. "SETFILE=/usr/bin/SetFile" From 7353d1725b93d6caade70440f177e07178d48906 Mon Sep 17 00:00:00 2001 From: Kuai Wei Date: Fri, 28 Aug 2026 02:44:42 +0000 Subject: [PATCH 122/223] 8388288: RISC-V: Use Zicond instruction for encode/decode heap oop Reviewed-by: dzhang, fyang --- .../cpu/riscv/macroAssembler_riscv.cpp | 33 ++++-- .../bench/vm/compiler/EncodeDecodeBench.java | 104 ++++++++++++++++++ 2 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/EncodeDecodeBench.java diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index ec044b6f824d..154e3ea337fa 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3844,11 +3844,17 @@ void MacroAssembler::encode_heap_oop(Register d, Register s) { mv(d, s); } } else { - Label notNull; - sub(d, s, xheapbase); - bgez(d, notNull); - mv(d, zr); - bind(notNull); + if (UseZicond) { + assert_different_registers(s, t0); + sub(t0, s, xheapbase); + czero_eqz(d, t0, s); // d = s == 0 ? 0 : t0 + } else { + Label notNull; + sub(d, s, xheapbase); + bgez(d, notNull); + mv(d, zr); + bind(notNull); + } if (CompressedOops::shift() != 0) { assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); srli(d, d, CompressedOops::shift()); @@ -4060,11 +4066,18 @@ void MacroAssembler::decode_heap_oop(Register d, Register s) { slli(d, s, CompressedOops::shift()); } } else { - Label done; - mv(d, s); - beqz(s, done); - shadd(d, s, xheapbase, d, LogMinObjAlignmentInBytes); - bind(done); + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + if (UseZicond) { + assert_different_registers(s, t0); + shadd(t0, s, xheapbase, t0, LogMinObjAlignmentInBytes); + czero_eqz(d, t0, s); // d = s == 0 ? 0 : t0 + } else { + Label done; + mv(d, s); + beqz(s, done); + shadd(d, s, xheapbase, d, LogMinObjAlignmentInBytes); + bind(done); + } } verify_oop_msg(d, "broken oop in decode_heap_oop"); } diff --git a/test/micro/org/openjdk/bench/vm/compiler/EncodeDecodeBench.java b/test/micro/org/openjdk/bench/vm/compiler/EncodeDecodeBench.java new file mode 100644 index 000000000000..b20eba06aab7 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/EncodeDecodeBench.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * test encoding and decoding of heap oop + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +public class EncodeDecodeBench { + + static final class IntHolder { + public int value; + + IntHolder(int value) { + this.value = value; + } + } + + @Param("100000") + private int arraySize; + + @Param("0.1") + private double nullRatio; + + private IntHolder[] arrayA; + private IntHolder[] arrayB; + + @Setup + public void setup() { + arrayA = new IntHolder[arraySize]; + arrayB = new IntHolder[arraySize]; + Random random = new Random(0); + for (int i = 0; i < arraySize; i++) { + arrayA[i] = (random.nextDouble() < nullRatio) ? null : new IntHolder(i); + } + } + + @Benchmark + public IntHolder[] testEncode() { + IntHolder[] a = arrayA; + IntHolder[] b = arrayB; + for (int i = 0; i < a.length; i++) { + IntHolder holder = a[i]; + if (holder != null) { + holder.value += 1; + } + b[i] = holder; + } + return b; + } + + @Benchmark + public int testDecode() { + // Count the nulls so that the decode-and-compare branch is actually + // taken for some elements; see count() below. + return count(arrayA, null); + } + + // DONT_INLINE keeps 'v' unknown to C2 compiler. So C2 can not do + // null constatnt optimization. + // + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private int count(IntHolder[] a, IntHolder v) { + int cnt = 0; + for (int i = 0; i < a.length; i++) { + IntHolder holder = a[i]; + if (holder == v) { + cnt++; + } + } + return cnt; + } +} From 41d8208f39132733d90ba4615311e2d6c7e5d100 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Fri, 28 Aug 2026 05:50:54 +0000 Subject: [PATCH 123/223] 8389669: Add a fuzzer for the C2 vector logic cone (MacroLogicV) optimization Reviewed-by: thartmann, mhaessig --- .../vectorapi/TestVectorLogicConeFuzzer.java | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorLogicConeFuzzer.java diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLogicConeFuzzer.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLogicConeFuzzer.java new file mode 100644 index 000000000000..f600b470e9a7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLogicConeFuzzer.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8387204 + * @key randomness + * @summary Fuzzer for the C2 vector "logic cone" (MacroLogicV) packing optimization. + * @requires vm.compiler2.enabled + * @requires os.simpleArch == "x64" + * @modules jdk.incubator.vector + * @library /test/lib / + * @compile ../../compiler/lib/verify/Verify.java + * @run driver ${test.main.class} + */ + +package compiler.vectorapi; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.Random; + +import jdk.test.lib.Utils; + +import compiler.lib.compile_framework.CompileFramework; + +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.scope; +import static compiler.lib.template_framework.Template.let; + +import compiler.lib.template_framework.library.Expression; +import compiler.lib.template_framework.library.Expression.Nesting; +import compiler.lib.template_framework.library.PrimitiveType; +import compiler.lib.template_framework.library.TestFrameworkClass; +import compiler.lib.template_framework.library.VectorType; + +/** + * Fuzzer for the vector logic-cone (MacroLogicV) optimization. + * + *

      The generated tests build random expression trees using only bitwise logic + * operations, fed by exactly three input vectors, so that C2's + * {@code Compile::optimize_logic_cones} folds them into {@code MacroLogicV} (ternary + * truth-table) nodes. + * + *

      Predication is fuzzed too: a cone freely mixes non-predicated operations with + * predicated ones, and a cone may use more than one mask ({@code m0}, {@code m1}). + * + */ +public class TestVectorLogicConeFuzzer { + private static final Random RANDOM = Utils.getRandomInstance(); + + // A non-predicated MacroLogicV is a pure bitwise fold, so it is inferred for every + // integral element type; only the vector size matters (>= 128-bit, see the AVX512VL + // requirement in Matcher::match_rule_supported_vector). Byte and short are therefore + // covered as well, and only predication is restricted (see canPredicate below). + private static final List LOGIC_TYPES = List.of( + VectorType.BYTE_128, VectorType.BYTE_256, VectorType.BYTE_512, + VectorType.SHORT_128, VectorType.SHORT_256, VectorType.SHORT_512, + VectorType.INT_128, VectorType.INT_256, VectorType.INT_512, + VectorType.LONG_128, VectorType.LONG_256, VectorType.LONG_512 + ); + + private static final int SAMPLES_PER_TYPE = 15; + + // A predicated MacroLogicV maps to masked x86 VPTERNLOGD/Q, which is only defined for 32- + // and 64-bit lanes; Matcher::match_rule_supported_vector_masked rejects any other element + // type. Cones over byte and short are therefore generated non-predicated only. + private static boolean canPredicate(VectorType.Vector t) { + String carrier = t.elementType.carrierTypeName(); + return carrier.equals("int") || carrier.equals("long"); + } + + // Maximum number of distinct masks a single cone may use. A cone using one mask can pack + // entirely into a predicated MacroLogicV; a cone using two masks forces the packing logic + // to keep the differently-predicated parts apart. + private static final int MAX_MASKS = 2; + + // Logic-only operation pool for a given vector type: the non-predicated operations plus, + // for each of the "numMasks" masks m0..m declared in the generated method, the + // predicated counterparts. Cones are nested from this pool at random, so they mix + // non-predicated ops, ops sharing a mask, and ops under different masks. + // + // The operation set is exactly AndV, OrV, XorV and Not. Not is a unary op that C2 lowers to + // a XorV with an all-ones vector; both encodings are generated: + // - all-ones in in(2): v.not() / v.lanewise(NOT, m) + // - all-ones in in(1): allOnes.lanewise(XOR, v [, m]) + private static List logicOps(VectorType.Vector t, int numMasks) { + String allOnes = t.name() + ".broadcast(" + t.speciesName + ", -1)"; + List ops = new ArrayList<>(List.of( + Expression.make(t, "", t, ".lanewise(VectorOperators.AND, ", t, ")"), // AndV + Expression.make(t, "", t, ".lanewise(VectorOperators.OR, ", t, ")"), // OrV + Expression.make(t, "", t, ".lanewise(VectorOperators.XOR, ", t, ")"), // XorV + Expression.make(t, "", t, ".not()"), // Not, all-ones in in(2) + Expression.make(t, allOnes + ".lanewise(VectorOperators.XOR, ", t, ")") // Not, all-ones in in(1) + )); + for (int i = 0; i < numMasks; i++) { + String m = ", m" + i + ")"; + ops.add(Expression.make(t, "", t, ".lanewise(VectorOperators.AND, ", t, m)); // AndV + ops.add(Expression.make(t, "", t, ".lanewise(VectorOperators.OR, ", t, m)); // OrV + ops.add(Expression.make(t, "", t, ".lanewise(VectorOperators.XOR, ", t, m)); // XorV + ops.add(Expression.make(t, "", t, ".lanewise(VectorOperators.NOT, m" + i + ")")); // Not, all-ones in in(2) + ops.add(Expression.make(t, allOnes + ".lanewise(VectorOperators.XOR, ", t, m)); // Not, all-ones in in(1) + } + return ops; + } + + public static void main(String[] args) { + CompileFramework comp = new CompileFramework(); + comp.addJavaSourceCode("compiler.vectorapi.templated.LogicConeTemplated", generate(comp)); + comp.compile("--add-modules=jdk.incubator.vector"); + + List vmArgs = new ArrayList<>(List.of( + "--add-modules=jdk.incubator.vector" + )); + vmArgs.addAll(Arrays.asList(args)); + + comp.invoke("compiler.vectorapi.templated.LogicConeTemplated", "main", + new Object[] { vmArgs.toArray(new String[0]) }); + } + + public static String generate(CompileFramework comp) { + List tests = new ArrayList<>(); + + // Emit the LibraryRNG helper class used to fill the input arrays. + tests.add(PrimitiveType.generateLibraryRNG()); + + // Body shared by the compiled ($test) and reference ($reference) methods. + var bodyTemplate = Template.make("expression", "arguments", "decls", + (Expression expression, List arguments, List decls) -> { + VectorType.Vector retType = (VectorType.Vector) expression.returnType; + return scope( + let("carrierType", retType.elementType.carrierTypeName()), + decls, + "#carrierType[] out = new #carrierType[1000];\n", + expression.asToken(arguments), ".intoArray(out, 0);\n", + "return out;\n" + ); + }); + + var testTemplate = Template.make("type", (VectorType.Vector type) -> { + int numMasks = canPredicate(type) ? RANDOM.nextInt(1, MAX_MASKS + 1) : 0; + + // Generate a cone with at least 3 leaves so it can be fed by exactly 3 inputs. + Expression expression; + int attempts = 0; + do { + int depth = RANDOM.nextInt(3, 8); // roughly the number of logic ops in the cone + expression = Expression.nestRandomly(type, logicOps(type, numMasks), depth, Nesting.EXACT); + } while (expression.argumentTypes.size() < 3 && ++attempts < 50); + + String carrier = type.elementType.carrierTypeName(); + + // MacroLogicV is a ternary (3-input) truth-table node, so it is only inferred + // when the whole cone is fed by exactly 3 distinct input vectors. Feed the leaves + // from v0, v1, v2 round-robin: this uses each input at least once and keeps the + // two operands of every binary op distinct, avoiding self-cancelling identities + // (e.g. v ^ v == 0) that would collapse the cone away from a MacroLogicV. + List useArgs = new ArrayList<>(); + for (int i = 0; i < expression.argumentTypes.size(); i++) { + var at = expression.argumentTypes.get(i); + if (!(at instanceof VectorType.Vector)) { + throw new RuntimeException("unexpected argument type in logic cone: " + at); + } + useArgs.add("v" + (i % 3)); + } + + // Declarations shared by the compiled and the reference method: each mask once, + // then v0..v2 loaded once from the three input arrays. + List decls = new ArrayList<>(); + for (int i = 0; i < numMasks; i++) { + decls.add(List.of("var m", Integer.toString(i), " = VectorMask.fromArray(", + type.speciesName, ", mask_arr_", Integer.toString(i), ", 0);\n")); + } + for (int j = 0; j < 3; j++) { + decls.add(List.of("var v", Integer.toString(j), " = ", type.name(), + ".fromArray(", type.speciesName, ", arg_", Integer.toString(j), ", 0);\n")); + } + + // Method arguments: the 3 input arrays followed by one array per mask. + List defineAndFill = new ArrayList<>(); + StringBuilder passArgs = new StringBuilder("arg_0, arg_1, arg_2"); + List receiveArgs = new ArrayList<>(); + receiveArgs.add(List.of(carrier, "[] arg_0, ", carrier, "[] arg_1, ", carrier, "[] arg_2")); + for (int j = 0; j < 3; j++) { + String a = "arg_" + j; + defineAndFill.add(List.of(carrier, "[] ", a, " = new ", carrier, "[1000];\n", + "LibraryRNG.fill(", a, ");\n")); + } + for (int i = 0; i < numMasks; i++) { + String ma = "mask_arr_" + i; + defineAndFill.add("boolean[] " + ma + " = new boolean[1000];\nLibraryRNG.fill(" + ma + ");\n"); + passArgs.append(", ").append(ma); + receiveArgs.add(", boolean[] " + ma); + } + + // MacroLogicV IR matching is only asserted for non-masked cones; masked + // cones may not pack into MacroLogicV (e.g. mixed masks or partial predication). + Object testMethodHeader = numMasks == 0 + ? """ + @IR(applyIf = {"UseAVX", "3"}, counts = {IRNode.MACRO_LOGIC_V, " > 0 "}) + @Test + public static Object $test( + """ + : """ + @Test + public static Object $test( + """; + + return scope( + let("leaves", expression.argumentTypes.size()), + let("masks", numMasks), + """ + // --- $test start (type: #type, leaves: #leaves, inputs: 3, masks: #masks) --- + @Run(test = "$test") + public void $run() { + """, + defineAndFill, + " Object r0 = $test(" + passArgs + ");\n", + " Object r1 = $reference(" + passArgs + ");\n", + " Verify.checkEQ(r0, r1);\n", + """ + } + + """, + testMethodHeader, + receiveArgs, + """ + ) { + """, + bodyTemplate.asToken(expression, useArgs, decls), + """ + } + + @DontCompile + public static Object $reference( + """, + receiveArgs, + """ + ) { + """, + bodyTemplate.asToken(expression, useArgs, decls), + """ + } + // --- $test end --- + """ + ); + }); + + for (VectorType.Vector type : LOGIC_TYPES) { + for (int i = 0; i < SAMPLES_PER_TYPE; i++) { + tests.add(testTemplate.asToken(type)); + } + } + + return TestFrameworkClass.render( + "compiler.vectorapi.templated", "LogicConeTemplated", + Set.of("compiler.lib.verify.*", + "compiler.lib.generators.*", + "jdk.incubator.vector.*", + "java.util.Random", + "jdk.test.lib.Utils"), + comp.getEscapedClassPathOfCompiledClasses(), + tests); + } +} From f11c9fca7e45466d3cb6688c053be4ba59eb10f0 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 28 Aug 2026 06:49:22 +0000 Subject: [PATCH 124/223] 8340088: Stack tracing tests of sleeping thread should be more resilient to code changes Reviewed-by: dholmes, sspitsyn, coleenp --- .../monitoring/share/ThreadController.java | 37 ++++++---- .../share/thread/SleepingThread.java | 33 ++++++--- .../monitoring/stress/thread/strace001.java | 67 +++++++++---------- 3 files changed, 78 insertions(+), 59 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java index 9d121b9a94f7..5ee794211f32 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -653,21 +653,9 @@ public SleepingThread(ThreadController controller, String name, Log log, Threads this.threadsGroupLocks = threadsGroupLocks; - expectedLength += 4; + expectedLength++; expectedMethods.add(Thread.class.getName() + ".sleep"); - expectedMethods.add(Thread.class.getName() + ".sleepNanos"); - expectedMethods.add(Thread.class.getName() + ".sleepNanos0"); - expectedMethods.add(Thread.class.getName() + ".beforeSleep"); - expectedMethods.add(Thread.class.getName() + ".afterSleep"); - expectedMethods.add(Thread.class.getName() + ".currentCarrierThread"); - expectedMethods.add(Thread.class.getName() + ".currentThread"); - // jdk.internal.event.ThreadSleepEvent not accessible - expectedMethods.add("java.lang.Object."); - expectedMethods.add("jdk.internal.event.Event."); - expectedMethods.add("jdk.internal.event.ThreadSleepEvent."); - expectedMethods.add("jdk.internal.event.ThreadSleepEvent."); - expectedMethods.add("jdk.internal.event.ThreadSleepEvent.isEnabled"); expectedMethods.add(SleepingThread.class.getName() + ".run"); switch (controller.invocationType) { @@ -698,6 +686,27 @@ public boolean checkState(Thread.State state) { return state == Thread.State.TIMED_WAITING; } + public boolean checkStackTrace(StackTraceElement[] elements) { + if (elements.length == 0) { + // ThreadMXBean.getThreadInfo(long) and getThreadInfo(long[]) return + // ThreadInfo without a stack trace, so there is nothing to check. + return true; + } + // Only the java.lang.Thread.sleep entry frame is required here. + // Frames above it are implementation details of sleep that change + // between releases, so they are not checked. + for (int i = elements.length - 1; i >= 0; i--) { + if (elements[i].getClassName().equals("java.lang.Thread") + && elements[i].getMethodName().equals("sleep")) { + // The frames below the sleep entry are the test's own stack and still get checked. + return super.checkStackTrace( + Arrays.copyOfRange(elements, i, elements.length)); + } + } + logger.complain("No java.lang.Thread.sleep frame in the stack trace"); + return false; + } + public void run() { try { switch (controller.invocationType) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java index 217c2cdfdc82..300b660b89af 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package nsk.monitoring.share.thread; import nsk.share.log.Log; +import java.util.Arrays; import java.lang.management.ThreadInfo; import java.lang.management.MonitorInfo; import java.lang.management.LockInfo; @@ -36,16 +37,6 @@ public class SleepingThread extends RecursiveMonitoringThread { private Object readyLock = new Object(); private static final String[] expectedMethods = { "java.lang.Thread.sleep", - "java.lang.Thread.sleepNanos", - "java.lang.Thread.sleepNanos0", - "java.lang.Thread.beforeSleep", - "java.lang.Thread.afterSleep", - "java.util.concurrent.TimeUnit.toNanos", - "java.lang.Object.", - "jdk.internal.event.Event.", - "jdk.internal.event.ThreadSleepEvent.", - "jdk.internal.event.ThreadSleepEvent.", - "jdk.internal.event.ThreadSleepEvent.isEnabled", "nsk.monitoring.share.thread.SleepingThread.runInside" }; @@ -99,6 +90,26 @@ protected void runInside() { } } + protected boolean checkStackTrace(StackTraceElement[] elements) { + if (elements.length == 0) { + // ThreadMXBean.getThreadInfo(long) and getThreadInfo(long[]) return + // ThreadInfo without a stack trace, so there is nothing to check. + return true; + } + // Only the java.lang.Thread.sleep entry frame is required here. + // Frames above it are implementation details of sleep that change + // between releases, so they are not checked. + for (int i = elements.length - 1; i >= 0; i--) { + if (elements[i].getClassName().equals("java.lang.Thread") + && elements[i].getMethodName().equals("sleep")) { + // The frames below the sleep entry are the test's own stack and still get checked. + return super.checkStackTrace(Arrays.copyOfRange(elements, i, elements.length)); + } + } + log.info("No java.lang.Thread.sleep frame in stack trace for: " + this); + return false; + } + protected boolean isStackTraceElementExpected(StackTraceElement element) { return super.isStackTraceElementExpected(element) || checkStackTraceElement(element, expectedMethods); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java index 0700032f6a7c..74d54d8e31cd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ public class strace001 { private static int depth; private static int threadCount; private static String[] expectedTrace; - private static String[] expectedSystemTrace; private static ThreadMonitor monitor; private static ThreadController controller; @@ -138,23 +137,6 @@ public static int run(String[] argv, PrintStream out) { // Fill expectedTrace array according to the invocation type that is set in // test options private static boolean fillTrace() { - expectedSystemTrace = new String[]{ - "java.lang.Thread.sleep", - "java.lang.Thread.sleepNanos", - "java.lang.Thread.sleepNanos0", - "java.lang.Thread.beforeSleep", - "java.lang.Thread.afterSleep", - "java.lang.Thread.yield", - "java.lang.Thread.yield0", - "java.lang.Thread.currentCarrierThread", - "java.lang.Thread.currentThread", - "java.util.concurrent.TimeUnit.toNanos", - "jdk.internal.event.ThreadSleepEvent.", - "java.lang.Object.", - "jdk.internal.event.Event.", - "jdk.internal.event.ThreadSleepEvent.", - "jdk.internal.event.ThreadSleepEvent.isEnabled" - }; switch (controller.getInvocationType()) { case ThreadController.JAVA_TYPE: @@ -206,15 +188,29 @@ private static void printStackTrace(StackTraceElement[] elements) { // The method performs checks of the stack trace private static boolean checkTrace(StackTraceElement[] elements) { - int length = elements.length; - // The length of the trace must not be greater than - // expectedLength. Number of recursionJava() or - // recursionNative() methods must not be greater than depth, - // also one run() and one waitForSign(), plus whatever can be - // reached from Thread.yield or Thread.sleep. - int expectedLength = depth + 7; boolean result = true; + // Find the innermost frame that belongs to the test's own code. + // Any frames above it come from the implementation of Thread.sleep + // or Thread.yield, which changes between releases, so they are + // not checked. + int firstOwn = -1; + for (int i = 0; i < elements.length; i++) { + if (isTestFrame(elements[i])) { + firstOwn = i; + break; + } + } + if (firstOwn < 0) { + log.complain("No frames of " + THREAD_NAME + " in the stack trace"); + return false; + } + + // The number of recursionJava() or recursionNative() frames must not + // be greater than depth, plus one run() and one waitForSign(). + int length = elements.length - firstOwn; + int expectedLength = depth + expectedTrace.length; + // Check the length of the trace if (length > expectedLength) { log.complain("Length of the stack trace is " + length + ", but " @@ -223,14 +219,12 @@ private static boolean checkTrace(StackTraceElement[] elements) { } // Check each element of the snapshot - for (int i = 0; i < elements.length; i++) { + for (int i = firstOwn; i < elements.length; i++) { if (i == elements.length - 1) { - // The latest method of the snapshot must be RunningThread.run() if ( !checkLastElement(elements[i]) ) result = false; } else { - // getClassName() and getMethodName() must return correct values // for each element if ( !checkElement(i, elements[i]) ) @@ -240,6 +234,16 @@ private static boolean checkTrace(StackTraceElement[] elements) { return result; } + // The method checks whether the element belongs to the test's own code. + private static boolean isTestFrame(StackTraceElement element) { + String name = element.getClassName() + "." + element.getMethodName(); + for (int i = 0; i < expectedTrace.length; i++) { + if (expectedTrace[i].equals(name)) + return true; + } + return false; + } + // The method checks that StackTraceElement.getClassName() and // StackTraceElement.getMethodName() return expected values private static boolean checkElement(int n, StackTraceElement element) { @@ -251,11 +255,6 @@ private static boolean checkElement(int n, StackTraceElement element) { return true; } - // Implementation of sleep/wait/yield - for (int i = 0; i < expectedSystemTrace.length; i++) { - if (expectedSystemTrace[i].equals(name)) - return true; - } log.complain("Unexpected " + n + " element of the stack trace:\n\t" + name); From 1811244fd810c5a033133330205bb2247221b181 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Fri, 28 Aug 2026 07:04:01 +0000 Subject: [PATCH 125/223] 8391315: [BACKOUT] Not all --long-options accept space as seperator Reviewed-by: dholmes, alanb, iris --- src/java.base/share/native/libjli/java.c | 30 +----- .../TestEnableNativeAccess.java | 17 +--- .../java/lang/Object/FinalizationOption.java | 71 +++---------- .../Object/InvalidFinalizationOption.java | 17 ++-- .../mutateFinals/cli/CommandLineTest.java | 99 ++++++------------- .../sun/misc/UnsafeMemoryAccessWarnings.java | 90 ++++++----------- 6 files changed, 87 insertions(+), 237 deletions(-) diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index 30d281ded2fe..bf2d309e8e8f 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -727,8 +727,7 @@ IsModuleOption(const char* name) { JLI_StrCmp(name, "--add-exports") == 0 || JLI_StrCmp(name, "--add-opens") == 0 || JLI_StrCmp(name, "--add-reads") == 0 || - JLI_StrCmp(name, "--patch-module") == 0 || - JLI_StrCmp(name, "--enable-final-field-mutation") == 0; + JLI_StrCmp(name, "--patch-module") == 0; } static jboolean @@ -740,21 +739,7 @@ IsLongFormModuleOption(const char* name) { JLI_StrCCmp(name, "--limit-modules=") == 0 || JLI_StrCCmp(name, "--add-exports=") == 0 || JLI_StrCCmp(name, "--add-reads=") == 0 || - JLI_StrCCmp(name, "--patch-module=") == 0 || - JLI_StrCCmp(name, "--enable-final-field-mutation=") == 0; -} - -/* - * Test if the given name is a non-module VM white-space option that - * will be passed to the VM with its corresponding long-form option - * name and "=" delimiter. - */ -static jboolean -IsNonModuleVMWhiteSpaceOption(const char* name) { - return JLI_StrCmp(name, "--illegal-native-access") == 0 || - JLI_StrCmp(name, "--illegal-final-field-mutation") == 0 || - JLI_StrCmp(name, "--sun-misc-unsafe-memory-access") == 0 || - JLI_StrCmp(name, "--finalization") == 0; + JLI_StrCCmp(name, "--patch-module=") == 0; } /* @@ -763,8 +748,7 @@ IsNonModuleVMWhiteSpaceOption(const char* name) { jboolean IsWhiteSpaceOption(const char* name) { return IsModuleOption(name) || - IsLauncherOption(name) || - IsNonModuleVMWhiteSpaceOption(name); + IsLauncherOption(name); } /* @@ -1141,7 +1125,7 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) { } kind = IsLauncherMainOption(arg) ? LAUNCHER_MAIN_OPTION : LAUNCHER_OPTION_WITH_ARGUMENT; - } else if (IsModuleOption(arg) || IsNonModuleVMWhiteSpaceOption(arg)) { + } else if (IsModuleOption(arg)) { kind = VM_LONG_OPTION_WITH_ARGUMENT; if (has_arg) { value = *argv; @@ -1255,12 +1239,6 @@ ParseArguments(int *pargc, char ***pargv, } else if (kind == VM_LONG_OPTION_WITH_ARGUMENT) { AddLongFormOption(option, value); } - /* - * Normalize a missing argument to the equivalent "--option=" form - * and let the subsequent option validation handle the empty value. - */ - } else if (!has_arg && IsNonModuleVMWhiteSpaceOption(arg)) { - AddLongFormOption(option, ""); /* * Error missing argument */ diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java index aca798c888ef..43d6e747935b 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,6 @@ public Object[][] succeedCases() { { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"), new String[]{} }, { "panama_all_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, - { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access", "allow"} }, }; } @@ -142,8 +141,7 @@ public void testRepeatedOption() throws Exception { } /** - * Tests invalid values for --enable-native-access and invalid or missing - * values for --illegal-native-access. + * Specifies bad value to --enable-native-access. */ @Test public void testBadValue() throws Exception { @@ -165,17 +163,6 @@ public void testBadValue() throws Exception { run("panama_deny_no_module_jni", PANAMA_JNI, failWithError("module panama_jni_load_module"), "--illegal-native-access=deny"); - run("panama_deny_no_module_jni", PANAMA_JNI, - failWithError("module panama_jni_load_module"), - "--illegal-native-access", "deny"); - // Missing value. - run("panama_enable_native_access", PANAMA_MAIN, - failWithError("Value specified to --illegal-native-access not recognized"), - "--illegal-native-access"); - // Invalid value. - run("panama_enable_native_access", PANAMA_MAIN, - failWithError("Value specified to --illegal-native-access not recognized"), - "--illegal-native-access", "bad"); } @Test diff --git a/test/jdk/java/lang/Object/FinalizationOption.java b/test/jdk/java/lang/Object/FinalizationOption.java index bcd340209caa..7d50412e26f0 100644 --- a/test/jdk/java/lang/Object/FinalizationOption.java +++ b/test/jdk/java/lang/Object/FinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -23,18 +23,12 @@ /* * @test - * @bug 8276422 8387729 + * @bug 8276422 * @summary add command-line option to disable finalization - * @library /test/lib - * @run main FinalizationOption enabled default - * @run main FinalizationOption enabled equals - * @run main FinalizationOption enabled whitespace - * @run main FinalizationOption disabled equals - * @run main FinalizationOption disabled whitespace + * @run main/othervm FinalizationOption yes + * @run main/othervm --finalization=enabled FinalizationOption yes + * @run main/othervm --finalization=disabled FinalizationOption no */ - -import jdk.test.lib.process.ProcessTools; - public class FinalizationOption { static volatile boolean finalizerWasCalled = false; @@ -110,54 +104,13 @@ static boolean checkFinalizerCalled(boolean expected) { return passed; } - /* - * Each @run invocation enters main() twice: - * - * 1. jtreg invokes main() with two arguments. This calls launch() - * to start a test process. - * - * 2. The launched test process invokes main() with one argument and - * performs the actual test. - */ - public static void main(String[] args) throws Exception { - switch (args.length) { - case 2: - launch(args[0], args[1]); - return; - case 1: - test(args[0]); - return; - default: - throw new AssertionError( - "expected one or two arguments"); - } - } - - /** - * Launch a test process with the given command-line option form. - */ - static void launch(String option, String form) throws Exception { - String[] javaArgs = switch (form) { - case "default" -> new String[] {"FinalizationOption", option}; - case "equals" -> new String[] {"--finalization=" + option, - "FinalizationOption", option}; - case "whitespace" -> new String[] {"--finalization", option, - "FinalizationOption", option}; - default -> throw new AssertionError("Unexpected option form: " + form); - }; - - ProcessTools.executeTestJava(javaArgs).shouldHaveExitValue(0); - } - - /** - * Perform the actual finalization test. - */ - static void test(String option) throws Exception { - boolean finalizationEnabled = switch (option) { - case "enabled" -> true; - case "disabled" -> false; - default -> throw new AssertionError( - "usage: FinalizationOption enabled|disabled"); + public static void main(String[] args) { + boolean finalizationEnabled = switch (args[0]) { + case "yes" -> true; + case "no" -> false; + default -> { + throw new AssertionError("usage: FinalizationOption yes|no"); + } }; boolean threadPass = checkFinalizerThread(finalizationEnabled); diff --git a/test/jdk/java/lang/Object/InvalidFinalizationOption.java b/test/jdk/java/lang/Object/InvalidFinalizationOption.java index 8dcaf153368b..f87ecfe9045b 100644 --- a/test/jdk/java/lang/Object/InvalidFinalizationOption.java +++ b/test/jdk/java/lang/Object/InvalidFinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8276422 8387729 + * @bug 8276422 * @summary Invalid/missing values for the finalization option should be rejected * @library /test/lib * @run driver InvalidFinalizationOption @@ -34,17 +34,12 @@ public class InvalidFinalizationOption { public static void main(String[] args) throws Exception { - record TestData(String[] arg, String expected) { } + record TestData(String arg, String expected) { } TestData[] testData = { - new TestData(new String[] { "--finalization" }, - "Invalid finalization value"), - new TestData(new String[] { "--finalization=" }, - "Invalid finalization value"), - new TestData(new String[] { "--finalization=azerty" }, - "Invalid finalization value"), - new TestData(new String[] { "--finalization", "azerty" }, - "Invalid finalization value") + new TestData("--finalization", "Unrecognized option"), + new TestData("--finalization=", "Invalid finalization value"), + new TestData("--finalization=azerty", "Invalid finalization value") }; for (var data : testData) { diff --git a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java index 00a854f06baa..34f9bb2bd5b0 100644 --- a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java +++ b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8353835 8387729 + * @bug 8353835 * @summary Test the command line option --enable-final-field-mutation * @library /test/lib * @build CommandLineTestHelper @@ -84,27 +84,18 @@ void testDefault() throws Exception { */ @Test void testAllow() throws Exception { - for (String[] opt : optionForms("--illegal-final-field-mutation", "allow")) { - test("testFieldSetInt", opt) - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldHaveExitValue(0); - } - - for (String[] opt : optionForms("--enable-final-field-mutation", "ALL-UNNAMED")) { - test("testFieldSetInt", opt) - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldHaveExitValue(0); - } + test("testFieldSetInt", "--illegal-final-field-mutation=allow") + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldHaveExitValue(0); - // allow ALL-UNNAMED, deny by default - test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") + test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); - test("testFieldSetInt", "--enable-final-field-mutation", "ALL-UNNAMED", "--illegal-final-field-mutation", "deny") + // allow ALL-UNNAMED, deny by default + test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); @@ -131,14 +122,12 @@ void testAllow() throws Exception { */ @Test void testWarn() throws Exception { - for (String[] opt : optionForms("--illegal-final-field-mutation", "warn")) { - test("testFieldSetInt", opt) - .shouldContain(WARNING_LINE1) - .shouldContain(WARNING_MUTATED) - .shouldContain(WARNING_LINE3) - .shouldContain(WARNING_LINE4) - .shouldHaveExitValue(0); - } + test("testFieldSetInt", "--illegal-final-field-mutation=warn") + .shouldContain(WARNING_LINE1) + .shouldContain(WARNING_MUTATED) + .shouldContain(WARNING_LINE3) + .shouldContain(WARNING_LINE4) + .shouldHaveExitValue(0); test("testUnreflectSetter", "--illegal-final-field-mutation=warn") .shouldContain(WARNING_LINE1) @@ -173,15 +162,13 @@ void testWarn() throws Exception { */ @Test void testDebug() throws Exception { - for (String[] opt : optionForms("--illegal-final-field-mutation", "debug")) { - test("testFieldSetInt+testUnreflectSetter", opt) - .shouldContain("Final field value in class " + HELPER) - .shouldContain(WARNING_MUTATED) - .shouldContain("java.lang.reflect.Field.setInt") - .shouldContain(WARNING_UNREFLECTED) - .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") - .shouldHaveExitValue(0); - } + test("testFieldSetInt+testUnreflectSetter", "--illegal-final-field-mutation=debug") + .shouldContain("Final field value in class " + HELPER) + .shouldContain(WARNING_MUTATED) + .shouldContain("java.lang.reflect.Field.setInt") + .shouldContain(WARNING_UNREFLECTED) + .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") + .shouldHaveExitValue(0); test("testUnreflectSetter+testFieldSetInt", "--illegal-final-field-mutation=debug") .shouldContain("Final field value in class " + HELPER) @@ -197,13 +184,11 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - for (String[] opt : optionForms("--illegal-final-field-mutation", "deny")) { - test("testFieldSetInt", opt) - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldContain("java.lang.IllegalAccessException") - .shouldNotHaveExitValue(0); - } + test("testFieldSetInt", "--illegal-final-field-mutation=deny") + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldContain("java.lang.IllegalAccessException") + .shouldNotHaveExitValue(0); test("testUnreflectSetter", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) @@ -217,17 +202,7 @@ void testDeny() throws Exception { */ @Test void testLastOneWins() throws Exception { - test("testFieldSetInt", - "--illegal-final-field-mutation=allow", - "--illegal-final-field-mutation=deny") - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldContain("java.lang.IllegalAccessException") - .shouldNotHaveExitValue(0); - - test("testFieldSetInt", - "--illegal-final-field-mutation", "allow", - "--illegal-final-field-mutation", "deny") + test("testFieldSetInt", "--illegal-final-field-mutation=allow", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldContain("java.lang.IllegalAccessException") @@ -245,11 +220,9 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - for (String[] opt : optionForms("--illegal-final-field-mutation", value)) { - test("testFieldSetInt", opt) - .shouldContain("Value specified to --illegal-final-field-mutation not recognized") - .shouldNotHaveExitValue(0); - } + test("testFieldSetInt", "--illegal-final-field-mutation=" + value) + .shouldContain("Value specified to --illegal-final-field-mutation not recognized") + .shouldNotHaveExitValue(0); } /** @@ -318,14 +291,4 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { private int countStrings(String input, String substring) { return input.split(Pattern.quote(substring)).length - 1; } - - /** - * Returns the given option in both supported argument forms. - */ - private String[][] optionForms(String option, String value) { - return new String[][] { - { option + "=" + value }, - { option, value } - }; - } } diff --git a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java index f6ceb95c0cb2..0e71dfdc1940 100644 --- a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java +++ b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8331670 8338383 8387729 + * @bug 8331670 8338383 * @summary Basic test for --sun-misc-unsafe-memory-access= * @library /test/lib * @compile TryUnsafeMemoryAccess.java @@ -59,17 +59,16 @@ void testDefault(String input) throws Exception { */ @Test void testAllow() throws Exception { - for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "allow")) { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) - .shouldHaveExitValue(0) - .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") - .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") - .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); - } + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", + "--sun-misc-unsafe-memory-access=allow") + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") + .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); } /** @@ -81,9 +80,7 @@ void testAllow() throws Exception { "objectFieldOffset+putLong+getLong" }) void testWarn(String input) throws Exception { - for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "warn")) { - testOneWarning(input, opt); - } + testOneWarning(input, "--sun-misc-unsafe-memory-access=warn"); } /** @@ -116,16 +113,15 @@ private void testOneWarning(String input, String... vmopts) throws Exception { */ @Test void testDebug() throws Exception { - for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "debug")) { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) - .shouldHaveExitValue(0) - .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") - .shouldContain("WARNING: sun.misc.Unsafe::putLong called") - .shouldContain("WARNING: sun.misc.Unsafe::getLong called") - .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); - } + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", + "--sun-misc-unsafe-memory-access=debug") + .shouldHaveExitValue(0) + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") + .shouldContain("WARNING: sun.misc.Unsafe::putLong called") + .shouldContain("WARNING: sun.misc.Unsafe::getLong called") + .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); } /** @@ -133,13 +129,11 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "deny")) { - test("allocateMemory+objectFieldOffset+invokeCleaner", opt) - .shouldHaveExitValue(0) - .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") - .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") - .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); - } + test("allocateMemory+objectFieldOffset+invokeCleaner", "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); } /** @@ -177,16 +171,8 @@ void testInvokeReflectively() throws Exception { @Test void testLastOneWins() throws Exception { test("allocateMemory+objectFieldOffset+invokeCleaner", - "--sun-misc-unsafe-memory-access=allow", - "--sun-misc-unsafe-memory-access=deny") - .shouldHaveExitValue(0) - .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") - .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") - .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); - - test("allocateMemory+objectFieldOffset+invokeCleaner", - "--sun-misc-unsafe-memory-access", "allow", - "--sun-misc-unsafe-memory-access", "deny") + "--sun-misc-unsafe-memory-access=allow", + "--sun-misc-unsafe-memory-access=deny") .shouldHaveExitValue(0) .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") @@ -199,11 +185,9 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", value)) { - test("allocateMemory", opt) - .shouldNotHaveExitValue(0) - .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); - } + test("allocateMemory", "--sun-misc-unsafe-memory-access=" + value) + .shouldNotHaveExitValue(0) + .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); } /** @@ -230,14 +214,4 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { .errorTo(System.err); return outputAnalyzer; } - - /** - * Returns the given option in both supported argument forms. - */ - private String[][] optionForms(String option, String value) { - return new String[][] { - { option + "=" + value }, - { option, value } - }; - } } From ba2ebcddd3007d0bc1ce62054ce46d8cced6fee5 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 28 Aug 2026 08:05:15 +0000 Subject: [PATCH 126/223] 8387026: Shenandoah: Cleanup and outline native barriers Reviewed-by: wkemper, kdnilsen --- .../gc/shenandoah/shenandoahBarrierSet.cpp | 216 ++++++- .../gc/shenandoah/shenandoahBarrierSet.hpp | 85 +-- .../shenandoahBarrierSet.inline.hpp | 556 ++++++------------ .../shenandoahBarrierSetStackChunk.cpp | 6 +- .../shenandoah/shenandoahClosures.inline.hpp | 7 +- .../gc/shenandoah/shenandoahForwarding.hpp | 5 - .../shenandoahForwarding.inline.hpp | 15 - .../share/gc/shenandoah/shenandoahHeap.cpp | 27 +- .../shenandoahReferenceProcessor.cpp | 3 +- .../share/gc/shenandoah/shenandoahRuntime.cpp | 24 +- src/hotspot/share/runtime/stackValue.cpp | 4 +- 11 files changed, 474 insertions(+), 474 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 1e839fab6554..107f126b44d5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -29,9 +29,14 @@ #include "gc/shenandoah/shenandoahBarrierSetStackChunk.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" +#include "gc/shenandoah/shenandoahForwarding.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahStackWatermark.hpp" +#include "memory/iterator.inline.hpp" +#include "oops/compressedOops.inline.hpp" #ifdef COMPILER1 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #endif @@ -94,8 +99,7 @@ bool ShenandoahBarrierSet::need_satb_barrier(DecoratorSet decorators, BasicType bool ShenandoahBarrierSet::need_card_barrier(DecoratorSet decorators, BasicType type) { if (!ShenandoahCardBarrier) return false; if (!is_reference_type(type)) return false; - bool in_heap = (decorators & IN_HEAP) != 0; - return in_heap; + return is_heap_access(decorators); } void ShenandoahBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { @@ -181,8 +185,51 @@ void ShenandoahBarrierSet::on_thread_detach(Thread *thread) { } } -void ShenandoahBarrierSet::write_ref_array(HeapWord* start, size_t count) { - assert(ShenandoahCardBarrier, "Should have been checked by caller"); +void ShenandoahBarrierSet::keepalive_barrier_slow(oop obj, Filter filter) { + if (!ShenandoahSATBBarrier) { + return; + } + assert(obj != nullptr, "Filtered by caller"); + assert(_heap->is_concurrent_mark_in_progress(), "Filtered by caller"); + + // Filter marked objects before hitting the SATB queues. The same predicate would + // be used by SATBMQ::filter to eliminate already marked objects downstream, but + // filtering here helps to avoid wasteful SATB queueing work to begin with. + if (((filter & FILTER_MARKED) != 0) && !_heap->requires_marking(obj)) { + return; + } + + shenandoah_assert_correct(nullptr, obj); + assert(_satb_mark_queue_set.is_active(), "only get here when SATB active"); + + SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(Thread::current()); + _satb_mark_queue_set.enqueue_known_active(queue, obj); +} + +template +oop ShenandoahBarrierSet::load_reference_barrier_slow(oop obj, T* load_addr) { + if (!ShenandoahLoadRefBarrier) { + return obj; + } + assert(_heap->has_forwarded_objects(), "Filtered by caller"); + assert(_heap->in_collection_set(obj), "Filtered by caller"); + oop fwd = ShenandoahForwarding::get_forwardee(obj); + if (obj == fwd && _heap->is_evacuation_in_progress()) { + Thread* t = Thread::current(); + fwd = _heap->evacuate_object(obj, t); + } + if (load_addr != nullptr && fwd != obj) { + // Since we are here and we know the load address, update the reference. + ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj); + } + return fwd; +} + +template oop ShenandoahBarrierSet::load_reference_barrier_slow(oop obj, oop* load_addr); +template oop ShenandoahBarrierSet::load_reference_barrier_slow(oop obj, narrowOop* load_addr); + +void ShenandoahBarrierSet::card_barrier_array_slow(HeapWord* start, size_t count) { + assert(ShenandoahCardBarrier, "Filtered by caller"); HeapWord* end = (HeapWord*)((char*) start + (count * heapOopSize)); // In the case of compressed oops, start and end may potentially be misaligned; @@ -199,3 +246,164 @@ void ShenandoahBarrierSet::write_ref_array(HeapWord* start, size_t count) { _heap->old_generation()->card_scan()->mark_range_as_dirty(aligned_start, (aligned_end - aligned_start)); } +// Clone barrier support +template +class ShenandoahUpdateEvacForCloneOopClosure : public BasicOopIterateClosure { +private: + ShenandoahHeap* const _heap; + const ShenandoahCollectionSet* const _cset; + Thread* const _thread; + + template + inline void do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (_cset->is_in(obj)) { + oop fwd = ShenandoahForwarding::get_forwardee(obj); + if (EVAC && obj == fwd) { + fwd = _heap->evacuate_object(obj, _thread); + } + shenandoah_assert_forwarded_except(p, obj, _heap->cancelled_gc()); + ShenandoahHeap::atomic_update_oop(fwd, p, o); + obj = fwd; + } + } + } + +public: + ShenandoahUpdateEvacForCloneOopClosure() : + _heap(ShenandoahHeap::heap()), + _cset(_heap->collection_set()), + _thread(Thread::current()) {} + + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } +}; + +void ShenandoahBarrierSet::clone_evacuation(oop obj) { + if (!ShenandoahCloneBarrier) { + return; + } + if (!need_bulk_update(cast_from_oop(obj))) { + return; + } + + ShenandoahUpdateEvacForCloneOopClosure cl; + obj->oop_iterate(&cl); +} + +void ShenandoahBarrierSet::clone_update(oop obj) { + if (!ShenandoahCloneBarrier) { + return; + } + if (!need_bulk_update(cast_from_oop(obj))) { + return; + } + + ShenandoahUpdateEvacForCloneOopClosure cl; + obj->oop_iterate(&cl); +} + +template +bool ShenandoahBarrierSet::is_above_tams(const ShenandoahMarkingContext* ctx, T* dst) const { + // TAMS for an old region is unreliable during a young-only mark, so overwritten pointers in old dst arrays must + // be enqueued to preserve old->young referents copied in and overwritten after init mark. See JDK-8373116. + return ctx->allocated_after_mark_start(reinterpret_cast(dst)) + && !(IS_GENERATIONAL + && _heap->heap_region_containing(dst)->is_old() + && _heap->is_concurrent_young_mark_in_progress()); +} + +inline bool ShenandoahBarrierSet::need_bulk_update(HeapWord* ary) const { + return ary < _heap->heap_region_containing(ary)->get_update_watermark(); +} + +template +void ShenandoahBarrierSet::arraycopy_marking(T* dst, size_t count) { + assert(_heap->is_concurrent_mark_in_progress(), "only during marking"); + if (!ShenandoahSATBBarrier) { + return; + } + + const ShenandoahMarkingContext* ctx = _heap->marking_context(); + // Everything allocated above TAMS is alive and doesn't need the barrier to keep it that way + if (is_above_tams(ctx, dst)) { + return; + } + + assert(!_heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded object status is sane"); + Thread* thread = Thread::current(); + SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread); + T* end = dst + count; + for (T* elem_ptr = dst; elem_ptr < end; ++elem_ptr) { + T o = RawAccess<>::oop_load(elem_ptr); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (!ctx->is_marked_strong(obj)) { + _satb_mark_queue_set.enqueue_known_active(queue, obj); + } + } + } +} + +template void ShenandoahBarrierSet::arraycopy_marking(oop* dst, size_t count); +template void ShenandoahBarrierSet::arraycopy_marking(narrowOop* dst, size_t count); +template void ShenandoahBarrierSet::arraycopy_marking(oop* dst, size_t count); +template void ShenandoahBarrierSet::arraycopy_marking(narrowOop* dst, size_t count); + +template +void ShenandoahBarrierSet::arraycopy_evacuation(T* src, size_t count) { + assert(_heap->is_evacuation_in_progress(), "only during evacuation"); + if (!need_bulk_update(reinterpret_cast(src))) { + return; + } + + assert(_heap->has_forwarded_objects(), "Forwarded object status is sane"); + Thread* thread = Thread::current(); + const ShenandoahCollectionSet* const cset = _heap->collection_set(); + T* end = src + count; + for (T* elem_ptr = src; elem_ptr < end; ++elem_ptr) { + T o = RawAccess<>::oop_load(elem_ptr); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (cset->is_in(obj)) { + oop fwd = ShenandoahForwarding::get_forwardee(obj); + if (obj == fwd) { + fwd = _heap->evacuate_object(obj, thread); + } + shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc()); + ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o); + } + } + } +} + +template void ShenandoahBarrierSet::arraycopy_evacuation(oop* src, size_t count); +template void ShenandoahBarrierSet::arraycopy_evacuation(narrowOop* src, size_t count); + +template +void ShenandoahBarrierSet::arraycopy_update(T* src, size_t count) { + assert(_heap->is_update_refs_in_progress(), "only during update-refs"); + if (!need_bulk_update(reinterpret_cast(src))) { + return; + } + + assert(_heap->has_forwarded_objects(), "Forwarded object status is sane"); + const ShenandoahCollectionSet* const cset = _heap->collection_set(); + T* end = src + count; + for (T* elem_ptr = src; elem_ptr < end; ++elem_ptr) { + T o = RawAccess<>::oop_load(elem_ptr); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (cset->is_in(obj)) { + oop fwd = ShenandoahForwarding::get_forwardee(obj); + shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc()); + ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o); + } + } + } +} + +template void ShenandoahBarrierSet::arraycopy_update(oop* src, size_t count); +template void ShenandoahBarrierSet::arraycopy_update(narrowOop* src, size_t count); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 4ae1f03a08da..83f0d42e2781 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -80,10 +80,11 @@ class ShenandoahBarrierSet: public BarrierSet { return (decorators & IN_NATIVE) != 0; } - void print_on(outputStream* st) const override; + static bool is_heap_access(DecoratorSet decorators) { + return (decorators & IN_HEAP) != 0; + } - template - inline void arraycopy_barrier(T* src, T* dst, size_t count, bool dest_uninit); + void print_on(outputStream* st) const override; // Support for optimizing compilers to call the barrier set on slow path allocations // that did not enter a TLAB. Used for e.g. ReduceInitialCardMarks to take any @@ -94,49 +95,68 @@ class ShenandoahBarrierSet: public BarrierSet { void on_thread_attach(Thread* thread) override; void on_thread_detach(Thread* thread) override; - template - inline void satb_barrier(T* field); - inline void satb_enqueue(oop value); - - inline void keep_alive_if_weak(DecoratorSet decorators, oop value); + enum Filter { + FILTER_NONE = 0, + FILTER_WEAK = (1 << 0), + FILTER_MARKED = (1 << 1), + FILTER_WEAK_AND_MARKED = FILTER_WEAK | FILTER_MARKED, + }; - inline void enqueue(oop obj, bool filter = true); + template + inline oop oop_load_post(DecoratorSet decorators, oop value, T* addr); - inline oop load_reference_barrier(oop obj); + template + inline void oop_store_pre(DecoratorSet decorators, T* addr, oop new_value); - template - inline oop load_reference_barrier_mutator(oop obj, T* load_addr); + template + inline void oop_cmpxchg_pre(DecoratorSet decorators, T* addr, oop compare_value, oop new_value); - template - inline oop load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr); + template + inline void oop_xchg_pre(DecoratorSet decorators, T* addr, oop new_value); template - inline oop oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value); + inline void oop_store_post(DecoratorSet decorators, T* addr, oop new_value); template - inline oop oop_xchg(DecoratorSet decorators, T* addr, oop new_value); + inline void keepalive_barrier(DecoratorSet decorators, T* addr, oop obj, Filter filter); - template - void write_ref_field_post(T* field, oop new_value); + template + inline oop load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr); - void write_ref_array(HeapWord* start, size_t count); + template + inline void arraycopy_barrier(T* src, T* dst, size_t count, bool dest_uninit); private: - template - void arraycopy_marking(T* dst, size_t count); + void keepalive_barrier_slow(oop obj, Filter filter); - template + template + oop load_reference_barrier_slow(oop obj, T* load_addr); + + template bool is_above_tams(const ShenandoahMarkingContext* ctx, T* dst) const; - template - inline void arraycopy_evacuation(T* src, size_t count); - template - inline void arraycopy_update(T* src, size_t count); + template + void arraycopy_marking(T* dst, size_t count); + + template + void arraycopy_evacuation(T* src, size_t count); + + template + void arraycopy_update(T* src, size_t count); + + void clone_evacuation(oop src); - template - inline void clone_work(oop src); + void clone_update(oop src); + + template + inline void card_barrier(T* field, oop new_value); + + inline void card_barrier_array(HeapWord* start, size_t count); + + void card_barrier_array_slow(HeapWord* start, size_t count); + + bool need_bulk_update(HeapWord* dst) const; - inline bool need_bulk_update(HeapWord* dst) const; public: // Callbacks for runtime accesses. template @@ -144,11 +164,8 @@ class ShenandoahBarrierSet: public BarrierSet { typedef BarrierSet::AccessBarrier Raw; private: - template - static oop oop_load_common(DecoratorSet resolved_decorators, T* addr); - - template - static void oop_store_common(T* addr, oop value); + static DecoratorSet resolve_unknown(oop base, ptrdiff_t offset); + static DecoratorSet resolve_unknown_to_strong(oop base, ptrdiff_t offset); public: // Heap oop accesses. These accessors get resolved when diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index b2f5fbad5cf0..a27516f97378 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -34,7 +34,6 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" -#include "gc/shenandoah/shenandoahForwarding.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" @@ -43,86 +42,14 @@ #include "memory/iterator.inline.hpp" #include "oops/oop.inline.hpp" -template -inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, T* load_addr) { - assert(ShenandoahLoadRefBarrier, "Should be enabled"); - - constexpr bool on_weak = HasDecorator::value; - constexpr bool on_phantom = HasDecorator::value; - - // Handle nulls. Strong loads filtered nulls with cset checks. - // Weak/phantom loads need to check for nulls here. - if (on_weak || on_phantom) { - if (obj == nullptr) { - return nullptr; - } - } else { - assert(obj != nullptr, "Should have been filtered before"); - } - - // Prevent resurrection of unreachable phantom (i.e. weak-native) references. - if (on_phantom && - _heap->is_concurrent_weak_root_in_progress() && - _heap->is_in_active_generation(obj) && - !_heap->marking_context()->is_marked(obj)) { - return nullptr; - } - - // Prevent resurrection of unreachable weak references. - if (on_weak && - _heap->is_concurrent_weak_root_in_progress() && - _heap->is_in_active_generation(obj) && - !_heap->marking_context()->is_marked_strong(obj)) { - return nullptr; - } - - // Weak/phantom loads need additional cset check. - if (on_phantom || on_weak) { - if (!_heap->has_forwarded_objects() || !_heap->in_collection_set(obj)) { - return obj; - } - } else { - shenandoah_assert_in_cset(load_addr, obj); - } - - oop fwd = ShenandoahForwarding::get_forwardee_mutator(obj); - if (obj == fwd) { - assert(_heap->is_evacuation_in_progress(), "evac should be in progress"); - Thread* const t = Thread::current(); - fwd = _heap->evacuate_object(obj, t); - } - - if (load_addr != nullptr && fwd != obj) { - // Since we are here and we know the load address, update the reference. - ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj); - } - - return fwd; -} - -inline oop ShenandoahBarrierSet::load_reference_barrier(oop obj) { - if (!ShenandoahLoadRefBarrier) { - return obj; - } - if (_heap->has_forwarded_objects() && _heap->in_collection_set(obj)) { - // Subsumes null-check - assert(obj != nullptr, "cset check must have subsumed null-check"); - oop fwd = ShenandoahForwarding::get_forwardee(obj); - if (obj == fwd && _heap->is_evacuation_in_progress()) { - Thread* t = Thread::current(); - return _heap->evacuate_object(obj, t); - } - return fwd; - } - return obj; -} - -template +template inline oop ShenandoahBarrierSet::load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr) { if (obj == nullptr) { return nullptr; } + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); + // Prevent resurrection of unreachable phantom (i.e. weak-native) references. if ((decorators & ON_PHANTOM_OOP_REF) != 0 && _heap->is_concurrent_weak_root_in_progress() && @@ -146,70 +73,54 @@ inline oop ShenandoahBarrierSet::load_reference_barrier(DecoratorSet decorators, return obj; } - oop fwd = load_reference_barrier(obj); - if (load_addr != nullptr && fwd != obj) { - // Since we are here and we know the load address, update the reference. - ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj); + // No need for the barrier if object is not forwarded. + if (!_heap->has_forwarded_objects() || !_heap->in_collection_set(obj)) { + return obj; } - return fwd; + return load_reference_barrier_slow(obj, load_addr); } -inline void ShenandoahBarrierSet::enqueue(oop obj, bool filter) { - assert(obj != nullptr, "checked by caller"); - shenandoah_assert_correct(nullptr, obj); - assert(_satb_mark_queue_set.is_active(), "only get here when SATB active"); - - // Filter marked objects before hitting the SATB queues. The same predicate would - // be used by SATBMQ::filter to eliminate already marked objects downstream, but - // filtering here helps to avoid wasteful SATB queueing work to begin with. - if (filter && !_heap->requires_marking(obj)) return; +template +inline void ShenandoahBarrierSet::keepalive_barrier(DecoratorSet decorators, T* addr, oop obj, Filter filter) { + // Uninitialized and no-keepalive loads/stores do not need barrier. + if (((decorators & IS_DEST_UNINITIALIZED) != 0) || + ((decorators & AS_NO_KEEPALIVE) != 0)) { + return; + } - SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(Thread::current()); - _satb_mark_queue_set.enqueue_known_active(queue, obj); -} + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); -template -inline void ShenandoahBarrierSet::satb_barrier(T *field) { - // Uninitialized and no-keepalive stores do not need barrier. - if (HasDecorator::value || - HasDecorator::value) { + // No need for barriers on weaks, if requested. Normally filtered for stores, accepted for loads. + if (((filter & FILTER_WEAK) != 0) && + (((decorators & ON_WEAK_OOP_REF) != 0) || + ((decorators & ON_PHANTOM_OOP_REF) != 0))) { return; } - // Stores to weak/phantom require no barrier. The original references would - // have been enqueued in the SATB buffer by the load barrier if they were needed. - if (HasDecorator::value || - HasDecorator::value) { + // No need for the barrier if marking is not in progress. + if (!_heap->is_concurrent_mark_in_progress()) { return; } - if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { - T heap_oop = RawAccess<>::oop_load(field); - if (!CompressedOops::is_null(heap_oop)) { - enqueue(CompressedOops::decode_not_null(heap_oop)); - } + if (addr != nullptr) { + assert(obj == nullptr, "Ambiguity: use addr or obj?"); + obj = RawAccess<>::oop_load(addr); } -} -inline void ShenandoahBarrierSet::satb_enqueue(oop value) { - if (value != nullptr && ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { - enqueue(value); + // Null objects require no barriers. + if (obj == nullptr) { + return; } -} -inline void ShenandoahBarrierSet::keep_alive_if_weak(DecoratorSet decorators, oop value) { - assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); - const bool on_strong_oop_ref = (decorators & ON_STRONG_OOP_REF) != 0; - const bool peek = (decorators & AS_NO_KEEPALIVE) != 0; - if (!peek && !on_strong_oop_ref) { - satb_enqueue(value); - } + keepalive_barrier_slow(obj, filter); } -template -inline void ShenandoahBarrierSet::write_ref_field_post(T* field, oop new_value) { - assert(ShenandoahCardBarrier, "Should have been checked by caller"); +template +inline void ShenandoahBarrierSet::card_barrier(T* field, oop new_value) { + if (!ShenandoahCardBarrier) { + return; + } if (new_value == nullptr) { // Null reference stores do not require card mark. @@ -233,241 +144,232 @@ inline void ShenandoahBarrierSet::write_ref_field_post(T* field, oop new_value) *byte = CardTable::dirty_card_val(); } +inline void ShenandoahBarrierSet::card_barrier_array(HeapWord* start, size_t count) { + if (!ShenandoahCardBarrier) { + return; + } + card_barrier_array_slow(start, count); +} + +template +inline oop ShenandoahBarrierSet::oop_load_post(DecoratorSet decorators, oop value, T* addr) { + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); + + shenandoah_assert_not_in_cset_loc_except(addr, !is_heap_access(decorators) || _heap->cancelled_gc()); + + // Perform LRB to handle evacuation and possibly weak loads. + value = load_reference_barrier(decorators, value, addr); + + // If weak load survived the LRB, we need to keep-alive the value. + if (!is_strong_access(decorators)) { + keepalive_barrier(decorators, (T*)nullptr, value, FILTER_MARKED); + } + + return value; +} + +template +inline void ShenandoahBarrierSet::oop_store_pre(DecoratorSet decorators, T* addr, oop new_value) { + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); + + shenandoah_assert_not_in_cset_loc_except(addr, !is_heap_access(decorators) || _heap->cancelled_gc()); + shenandoah_assert_not_in_cset_except(nullptr, new_value, new_value == nullptr || _heap->cancelled_gc()); + shenandoah_assert_not_forwarded_except(nullptr, new_value, new_value == nullptr || _heap->cancelled_gc()); + + shenandoah_assert_marked_if(nullptr, new_value, + !CompressedOops::is_null(new_value) && + _heap->is_evacuation_in_progress() && + !(_heap->active_generation()->is_young() && _heap->heap_region_containing(new_value)->is_old())); + + // Handle the previous value through SATB, as we are about to perform the store. + keepalive_barrier(decorators, addr, nullptr, FILTER_WEAK_AND_MARKED); +} + template -inline oop ShenandoahBarrierSet::oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value) { - shenandoah_assert_not_in_cset_except(nullptr, compare_value, (compare_value == nullptr || ShenandoahHeap::heap()->cancelled_gc())); - shenandoah_assert_not_in_cset_except(nullptr, new_value, (new_value == nullptr || ShenandoahHeap::heap()->cancelled_gc())); +inline void ShenandoahBarrierSet::oop_store_post(DecoratorSet decorators, T* addr, oop new_value) { + // Handle card table updates if needed. + if (is_heap_access(decorators)) { + card_barrier(addr, new_value); + } +} + +template +inline void ShenandoahBarrierSet::oop_cmpxchg_pre(DecoratorSet decorators, T* addr, oop compare_value, oop new_value) { + assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive"); + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "CAS should have resolved ref strength"); + assert((decorators & ON_STRONG_OOP_REF) != 0, "CAS only for strong refs"); + + shenandoah_assert_not_in_cset_loc_except(addr, !is_heap_access(decorators) || _heap->cancelled_gc()); + shenandoah_assert_not_in_cset_except(nullptr, compare_value, compare_value == nullptr || _heap->cancelled_gc()); + shenandoah_assert_not_in_cset_except(nullptr, new_value, new_value == nullptr || _heap->cancelled_gc()); + shenandoah_assert_not_forwarded_except(addr, compare_value, compare_value == nullptr || _heap->cancelled_gc()); + shenandoah_assert_not_forwarded_except(addr, new_value, new_value == nullptr || _heap->cancelled_gc()); // Handle the previous value through SATB, as we are about to perform the store. oop prev = RawAccess<>::oop_load(addr); - satb_enqueue(prev); + keepalive_barrier(decorators, (T*)nullptr, prev, FILTER_MARKED); // Perform LRB on location to fix it up for this and all following accesses. // This guarantees there are no false negatives due to concurrent evacuation, // and the value loaded later by CAS is sanitized by some LRB, or is null. load_reference_barrier(decorators, prev, addr); - - return RawAccess<>::oop_atomic_cmpxchg(addr, compare_value, new_value); } template -inline oop ShenandoahBarrierSet::oop_xchg(DecoratorSet decorators, T* addr, oop new_value) { - shenandoah_assert_not_in_cset_except(nullptr, new_value, (new_value == nullptr || ShenandoahHeap::heap()->cancelled_gc())); +inline void ShenandoahBarrierSet::oop_xchg_pre(DecoratorSet decorators, T* addr, oop new_value) { + assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive"); + assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "XCHG should have resolved ref strength"); + assert((decorators & ON_STRONG_OOP_REF) != 0, "XCHG only for strong refs"); + + shenandoah_assert_not_in_cset_loc_except(addr, !is_heap_access(decorators) || _heap->cancelled_gc()); + shenandoah_assert_not_in_cset_except(nullptr, new_value, new_value == nullptr || _heap->cancelled_gc()); + shenandoah_assert_not_forwarded_except(addr, new_value, new_value == nullptr || _heap->cancelled_gc()); // Handle the previous value through SATB, as we are about to perform the store. oop prev = RawAccess<>::oop_load(addr); - satb_enqueue(prev); + keepalive_barrier(decorators, (T*)nullptr, prev, FILTER_MARKED); // Perform LRB on location to fix it up for this and all following accesses. // This is purely opportunistic: we would not have any false negatives here. // This guarantees the value loaded later by XCHG is sanitized by some LRB, or is null. load_reference_barrier(decorators, prev, addr); +} - return RawAccess<>::oop_atomic_xchg(addr, new_value); +template +inline DecoratorSet ShenandoahBarrierSet::AccessBarrier::resolve_unknown(oop base, ptrdiff_t offset) { + return AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); } template -template -inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_common(DecoratorSet resolved_decorators, T* addr) { - // This raw access inherits decorators that are needed for proper memory ordering. - oop value = Raw::template oop_load(addr); - ShenandoahBarrierSet* bs = barrier_set(); - value = bs->load_reference_barrier(resolved_decorators, value, addr); - bs->keep_alive_if_weak(resolved_decorators, value); - return value; +inline DecoratorSet ShenandoahBarrierSet::AccessBarrier::resolve_unknown_to_strong(oop base, ptrdiff_t offset) { + // Unsafe operations come to this barrier set with ON_UNKNOWN_OOP_REF set. + // These are normally strong refs, but one can use Unsafe on Reference.referent. + // We cannot deal with that case. If application does Unsafe operations on + // Reference.referent field, this likely breaks weak reference semantics already. + // We upgrade the access to strong in (sometimes futile) attempt to maintain heap + // integrity, and assert in debug builds for better diagnostics. + assert((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0, "Only strong or unknown expected here"); + DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); + assert((resolved_decorators & ON_STRONG_OOP_REF) != 0, "Application error: Unsupported operation on weak location"); + return (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { - assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent"); - return oop_load_common(decorators, addr); + oop value = Raw::oop_load_not_in_heap(addr); + return barrier_set()->oop_load_post(decorators, value, addr); } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap(T* addr) { - assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent"); - return oop_load_common(decorators, addr); + oop value = Raw::oop_load_in_heap(addr); + return barrier_set()->oop_load_post(decorators, value, addr); } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap_at(oop base, ptrdiff_t offset) { - DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); - return oop_load_common(resolved_decorators, AccessInternal::oop_field_addr(base, offset)); -} - -template -template -inline void ShenandoahBarrierSet::AccessBarrier::oop_store_common(T* addr, oop value) { - shenandoah_assert_marked_if(nullptr, value, - !CompressedOops::is_null(value) && ShenandoahHeap::heap()->is_evacuation_in_progress() - && !(ShenandoahHeap::heap()->active_generation()->is_young() - && ShenandoahHeap::heap()->heap_region_containing(value)->is_old())); - shenandoah_assert_not_in_cset_if(addr, value, value != nullptr && !ShenandoahHeap::heap()->cancelled_gc()); - ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set(); - bs->satb_barrier(addr); - Raw::oop_store(addr, value); + DecoratorSet resolved_decorators = resolve_unknown(base, offset); + auto addr = AccessInternal::oop_field_addr(base, offset); + oop value = Raw::oop_load_in_heap(addr); + return barrier_set()->oop_load_post(resolved_decorators, value, addr); } template template inline void ShenandoahBarrierSet::AccessBarrier::oop_store_not_in_heap(T* addr, oop value) { - assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); - oop_store_common(addr, value); + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_store_pre(decorators, addr, value); + Raw::oop_store_not_in_heap(addr, value); + bs->oop_store_post(decorators, addr, value); } template template inline void ShenandoahBarrierSet::AccessBarrier::oop_store_in_heap(T* addr, oop value) { - shenandoah_assert_not_in_cset_loc_except(addr, ShenandoahHeap::heap()->cancelled_gc()); - shenandoah_assert_not_forwarded_except (addr, value, value == nullptr || ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahHeap::heap()->is_concurrent_mark_in_progress()); - - oop_store_common(addr, value); - if (ShenandoahCardBarrier) { - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - bs->write_ref_field_post(addr, value); - } + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_store_pre(decorators, addr, value); + Raw::oop_store_in_heap(addr, value); + bs->oop_store_post(decorators, addr, value); } template inline void ShenandoahBarrierSet::AccessBarrier::oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value) { - oop_store_in_heap(AccessInternal::oop_field_addr(base, offset), value); + auto addr = AccessInternal::oop_field_addr(base, offset); + + // In contrast to CASes, we resolve unknown to weak/phantom access, because some code + // legitimately enters here, e.g. for clearing Reference.referent. + DecoratorSet resolved_decorators = resolve_unknown(base, offset); + + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_store_pre(resolved_decorators, addr, value); + Raw::oop_store_in_heap(addr, value); + bs->oop_store_post(resolved_decorators, addr, value); } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive"); - assert((decorators & ON_STRONG_OOP_REF) != 0, "CAS only for strong refs"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - return bs->oop_cmpxchg(decorators, addr, compare_value, new_value); + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_cmpxchg_pre(decorators, addr, compare_value, new_value); + oop result = Raw::oop_atomic_cmpxchg_not_in_heap(addr, compare_value, new_value); + bs->oop_store_post(decorators, addr, new_value); + return result; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive"); - assert((decorators & ON_STRONG_OOP_REF) != 0, "CAS only for strong refs"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - oop result = bs->oop_cmpxchg(decorators, addr, compare_value, new_value); - if (ShenandoahCardBarrier) { - bs->write_ref_field_post(addr, new_value); - } + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_cmpxchg_pre(decorators, addr, compare_value, new_value); + oop result = Raw::oop_atomic_cmpxchg_in_heap(addr, compare_value, new_value); + bs->oop_store_post(decorators, addr, new_value); return result; } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive"); - assert((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0, "CAS only for strong refs OR unknown refs (Unsafe)"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - - // Unsafe.compareAndExchange/Set come here with ON_UNKNOWN_OOP_REF set. - // These are normally strong refs, but one can use Unsafe on Reference.referent. - // We cannot deal with that case. If application does Unsafe operations on - // Reference.referent field, this likely breaks weak reference semantics already. - // We upgrade the access to strong in (sometimes futile) attempt to maintain heap - // integrity, and assert in debug builds for better diagnostics. - DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); - assert((resolved_decorators & ON_STRONG_OOP_REF) != 0, "Application error: CAS on weak location"); - resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF; - auto addr = AccessInternal::oop_field_addr(base, offset); - oop result = bs->oop_cmpxchg(resolved_decorators, addr, compare_value, new_value); - if (ShenandoahCardBarrier) { - bs->write_ref_field_post(addr, new_value); - } + DecoratorSet resolved_decorators = resolve_unknown_to_strong(base, offset); + + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_cmpxchg_pre(resolved_decorators, addr, compare_value, new_value); + oop result = Raw::oop_atomic_cmpxchg_in_heap(addr, compare_value, new_value); + bs->oop_store_post(resolved_decorators, addr, new_value); return result; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_not_in_heap(T* addr, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive"); - assert((decorators & ON_STRONG_OOP_REF) != 0, "XCHG only for strong refs"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - return bs->oop_xchg(decorators, addr, new_value); + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_xchg_pre(decorators, addr, new_value); + oop result = Raw::oop_atomic_xchg_not_in_heap(addr, new_value); + bs->oop_store_post(decorators, addr, new_value); + return result; } template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap(T* addr, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive"); - assert((decorators & ON_STRONG_OOP_REF) != 0, "XCHG only for strong refs"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - oop result = bs->oop_xchg(decorators, addr, new_value); - if (ShenandoahCardBarrier) { - bs->write_ref_field_post(addr, new_value); - } + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_xchg_pre(decorators, addr, new_value); + oop result = Raw::oop_atomic_xchg_in_heap(addr, new_value); + bs->oop_store_post(decorators, addr, new_value); return result; } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value) { - assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive"); - assert((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0, "XCHG only for strong refs OR unknown refs (Unsafe)"); - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); - - // Unsafe.getAndSet comes here with ON_UNKNOWN_OOP_REF set. - // These are normally strong refs, but one can use Unsafe on Reference.referent. - // We cannot deal with that case. If application does Unsafe operations on - // Reference.referent field, this likely breaks weak reference semantics already. - // We upgrade the access to strong in (sometimes futile) attempt to maintain heap - // integrity, and assert in debug builds for better diagnostics. - DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset); - assert((resolved_decorators & ON_STRONG_OOP_REF) != 0, "Application error: XCHG on weak location"); - resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF; - auto addr = AccessInternal::oop_field_addr(base, offset); - oop result = bs->oop_xchg(resolved_decorators, addr, new_value); - if (ShenandoahCardBarrier) { - bs->write_ref_field_post(addr, new_value); - } - return result; -} + DecoratorSet resolved_decorators = resolve_unknown_to_strong(base, offset); -// Clone barrier support -template -class ShenandoahUpdateEvacForCloneOopClosure : public BasicOopIterateClosure { -private: - ShenandoahHeap* const _heap; - const ShenandoahCollectionSet* const _cset; - Thread* const _thread; - - template - inline void do_oop_work(T* p) { - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (_cset->is_in(obj)) { - oop fwd = ShenandoahForwarding::get_forwardee(obj); - if (EVAC && obj == fwd) { - fwd = _heap->evacuate_object(obj, _thread); - } - shenandoah_assert_forwarded_except(p, obj, _heap->cancelled_gc()); - ShenandoahHeap::atomic_update_oop(fwd, p, o); - obj = fwd; - } - } - } - -public: - ShenandoahUpdateEvacForCloneOopClosure() : - _heap(ShenandoahHeap::heap()), - _cset(_heap->collection_set()), - _thread(Thread::current()) {} - - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } -}; - -template -void ShenandoahBarrierSet::clone_work(oop obj) { - if (need_bulk_update(cast_from_oop(obj))) { - ShenandoahUpdateEvacForCloneOopClosure cl; - obj->oop_iterate(&cl); - } + ShenandoahBarrierSet* bs = barrier_set(); + bs->oop_xchg_pre(resolved_decorators, addr, new_value); + oop result = Raw::oop_atomic_xchg_in_heap(addr, new_value); + bs->oop_store_post(resolved_decorators, addr, new_value); + return result; } template @@ -476,12 +378,12 @@ void ShenandoahBarrierSet::AccessBarrier::clone_in_heap // Fix up src before doing the copy, if needed. const char gc_state = ShenandoahThreadLocalData::gc_state(Thread::current()); - if (gc_state != 0 && ShenandoahCloneBarrier) { - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); + if (gc_state != 0) { + ShenandoahBarrierSet* bs = barrier_set(); if ((gc_state & ShenandoahHeap::EVACUATION) != 0) { - bs->clone_work(src); + bs->clone_evacuation(src); } else if ((gc_state & ShenandoahHeap::UPDATE_REFS) != 0) { - bs->clone_work(src); + bs->clone_update(src); } } @@ -501,7 +403,7 @@ void ShenandoahBarrierSet::AccessBarrier::value_copy_in // If we do not have oops in the flat array, we can just do a raw copy. Raw::value_copy(src, dst); } else { - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); + ShenandoahBarrierSet* bs = barrier_set(); // addr() points at the payload start, the oop map offset are relative to // the object header, adjust address to account for this discrepancy. const address oop_map_adjusted_src_addr = src.addr() - md->payload_offset(); @@ -531,7 +433,7 @@ void ShenandoahBarrierSet::AccessBarrier::value_copy_in OopMapBlock* const end = map + md->nonstatic_oop_map_count(); while (map != end) { address dst_oop_address = oop_map_adjusted_dst_addr + map->offset(); - bs->write_ref_array((HeapWord*) dst_oop_address, map->count()); + bs->card_barrier_array((HeapWord*) dst_oop_address, map->count()); map++; } } @@ -579,16 +481,14 @@ OopCopyResult ShenandoahBarrierSet::AccessBarrier::oop_ T* dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw); bool dest_uninit = HasDecorator::value; - ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); + ShenandoahBarrierSet* bs = barrier_set(); bs->arraycopy_barrier(src, dst, length, dest_uninit); OopCopyResult result = Raw::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); - if (ShenandoahCardBarrier) { - bs->write_ref_array((HeapWord*) dst, length); - } + bs->card_barrier_array((HeapWord*) dst, length); return result; } -template +template void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count, bool dest_uninit) { if (count == 0) { // No elements to copy, no need for barrier @@ -616,96 +516,4 @@ void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count, bool } } -template -void ShenandoahBarrierSet::arraycopy_marking(T* dst, size_t count) { - assert(_heap->is_concurrent_mark_in_progress(), "only during marking"); - if (!ShenandoahSATBBarrier) { - return; - } - - const ShenandoahMarkingContext* ctx = _heap->marking_context(); - // Everything allocated above TAMS is alive and doesn't need the barrier to keep it that way - if (is_above_tams(ctx, dst)) { - return; - } - - assert(!_heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded object status is sane"); - Thread* thread = Thread::current(); - SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread); - T* end = dst + count; - for (T* elem_ptr = dst; elem_ptr < end; ++elem_ptr) { - T o = RawAccess<>::oop_load(elem_ptr); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (!ctx->is_marked_strong(obj)) { - _satb_mark_queue_set.enqueue_known_active(queue, obj); - } - } - } -} - -template -bool ShenandoahBarrierSet::is_above_tams(const ShenandoahMarkingContext* ctx, T* dst) const { - // TAMS for an old region is unreliable during a young-only mark, so overwritten pointers in old dst arrays must - // be enqueued to preserve old->young referents copied in and overwritten after init mark. See JDK-8373116. - return ctx->allocated_after_mark_start(reinterpret_cast(dst)) - && !(IS_GENERATIONAL - && _heap->heap_region_containing(dst)->is_old() - && _heap->is_concurrent_young_mark_in_progress()); -} - -inline bool ShenandoahBarrierSet::need_bulk_update(HeapWord* ary) const { - return ary < _heap->heap_region_containing(ary)->get_update_watermark(); -} - -template -void ShenandoahBarrierSet::arraycopy_evacuation(T* src, size_t count) { - assert(_heap->is_evacuation_in_progress(), "only during evacuation"); - if (!need_bulk_update(reinterpret_cast(src))) { - return; - } - - assert(_heap->has_forwarded_objects(), "Forwarded object status is sane"); - Thread* thread = Thread::current(); - const ShenandoahCollectionSet* const cset = _heap->collection_set(); - T* end = src + count; - for (T* elem_ptr = src; elem_ptr < end; ++elem_ptr) { - T o = RawAccess<>::oop_load(elem_ptr); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (cset->is_in(obj)) { - oop fwd = ShenandoahForwarding::get_forwardee(obj); - if (obj == fwd) { - fwd = _heap->evacuate_object(obj, thread); - } - shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc()); - ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o); - } - } - } -} - -template -void ShenandoahBarrierSet::arraycopy_update(T* src, size_t count) { - assert(_heap->is_update_refs_in_progress(), "only during update-refs"); - if (!need_bulk_update(reinterpret_cast(src))) { - return; - } - - assert(_heap->has_forwarded_objects(), "Forwarded object status is sane"); - const ShenandoahCollectionSet* const cset = _heap->collection_set(); - T* end = src + count; - for (T* elem_ptr = src; elem_ptr < end; ++elem_ptr) { - T o = RawAccess<>::oop_load(elem_ptr); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (cset->is_in(obj)) { - oop fwd = ShenandoahForwarding::get_forwardee(obj); - shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc()); - ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o); - } - } - } -} - #endif // SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetStackChunk.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetStackChunk.cpp index 224d9e1870a8..e881de8f4755 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetStackChunk.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetStackChunk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,10 @@ void ShenandoahBarrierSetStackChunk::decode_gc_mode(stackChunkOop chunk, OopIter oop ShenandoahBarrierSetStackChunk::load_oop(stackChunkOop chunk, oop* addr) { oop result = BarrierSetStackChunk::load_oop(chunk, addr); - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(result); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, result, (oop*)nullptr); } oop ShenandoahBarrierSetStackChunk::load_oop(stackChunkOop chunk, narrowOop* addr) { oop result = BarrierSetStackChunk::load_oop(chunk, addr); - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(result); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, result, (narrowOop*)nullptr); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 9beb47fa64a1..671d9586073a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -118,12 +118,7 @@ template void ShenandoahKeepAliveClosure::do_oop_work(T* p) { assert(ShenandoahHeap::heap()->is_concurrent_mark_in_progress(), "Only for concurrent marking phase"); assert(ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress() || !ShenandoahHeap::heap()->has_forwarded_objects(), "Not expected"); - - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - _bs->enqueue(obj); - } + _bs->keepalive_barrier(ON_STRONG_OOP_REF, p, nullptr, ShenandoahBarrierSet::FILTER_MARKED); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp index 6f2f124f6b11..ca064ee5f2e9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp @@ -36,11 +36,6 @@ class ShenandoahForwarding { */ static inline oop get_forwardee(oop obj); - /* Gets forwardee from the given object. Only from mutator thread. - * For a self-forwarded object, returns the object itself. - */ - static inline oop get_forwardee_mutator(oop obj); - /* Returns the raw value from forwardee slot. For a self-forwarded * object, returns the object itself. */ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp index 6bb58920eb96..df0154871d7c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp @@ -53,21 +53,6 @@ inline oop ShenandoahForwarding::get_forwardee_raw_unchecked(oop obj) { return obj; } -inline oop ShenandoahForwarding::get_forwardee_mutator(oop obj) { - // Same as above, but mutator thread cannot ever see null forwardee. - shenandoah_assert_correct(nullptr, obj); - assert(Thread::current()->is_Java_thread(), "Must be a mutator thread"); - - markWord mark = obj->mark(); - if (mark.is_marked()) { - HeapWord* fwdptr = (HeapWord*) mark.clear_lock_bits().to_pointer(); - assert(fwdptr != nullptr, "Forwarding pointer is never null here"); - return cast_to_oop(fwdptr); - } - // Self-forwarded or not forwarded: return the object itself. - return obj; -} - inline oop ShenandoahForwarding::get_forwardee(oop obj) { shenandoah_assert_correct(nullptr, obj); return get_forwardee_raw_unchecked(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 1411e7337d5f..df06e593d055 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1749,19 +1749,17 @@ class ObjectIterateScanRootClosure : public BasicOopIterateClosure { private: MarkBitMap* _bitmap; ShenandoahScanObjectStack* _oop_stack; - ShenandoahHeap* const _heap; - ShenandoahMarkingContext* const _marking_context; template void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); - if (_heap->is_concurrent_weak_root_in_progress() && !_marking_context->is_marked(obj)) { - // There may be dead oops in weak roots in concurrent root phase, do not touch them. + obj = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, obj, (T*)nullptr); + if (obj == nullptr) { + // Dead oop, cannot touch it. return; } - obj = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(obj); assert(oopDesc::is_oop(obj), "must be a valid oop"); if (!_bitmap->is_marked(obj)) { @@ -1772,8 +1770,7 @@ class ObjectIterateScanRootClosure : public BasicOopIterateClosure { } public: ObjectIterateScanRootClosure(MarkBitMap* bitmap, ShenandoahScanObjectStack* oop_stack) : - _bitmap(bitmap), _oop_stack(oop_stack), _heap(ShenandoahHeap::heap()), - _marking_context(_heap->marking_context()) {} + _bitmap(bitmap), _oop_stack(oop_stack) {} void do_oop(oop* p) { do_oop_work(p); } void do_oop(narrowOop* p) { do_oop_work(p); } }; @@ -1861,20 +1858,17 @@ class ShenandoahObjectIterateParScanClosure : public BasicOopIterateClosure { private: MarkBitMap* _bitmap; ShenandoahObjToScanQueue* _queue; - ShenandoahHeap* const _heap; - ShenandoahMarkingContext* const _marking_context; template void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); - if (_heap->is_concurrent_weak_root_in_progress() && !_marking_context->is_marked(obj)) { - // There may be dead oops in weak roots in concurrent root phase, do not touch them. + obj = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, obj, (T*)nullptr); + if (obj == nullptr) { + // Dead oop, cannot touch it. return; } - obj = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(obj); - assert(oopDesc::is_oop(obj), "Must be a valid oop"); if (_bitmap->par_mark(obj)) { _queue->push(ShenandoahMarkTask(obj)); @@ -1883,8 +1877,7 @@ class ShenandoahObjectIterateParScanClosure : public BasicOopIterateClosure { } public: ShenandoahObjectIterateParScanClosure(MarkBitMap* bitmap, ShenandoahObjToScanQueue* q) : - _bitmap(bitmap), _queue(q), _heap(ShenandoahHeap::heap()), - _marking_context(_heap->marking_context()) {} + _bitmap(bitmap), _queue(q) {} void do_oop(oop* p) { do_oop_work(p); } void do_oop(narrowOop* p) { do_oop_work(p); } }; @@ -1999,9 +1992,7 @@ ParallelObjectIteratorImpl* ShenandoahHeap::parallel_object_iterator(uint worker // Keep alive an object that was loaded with AS_NO_KEEPALIVE. void ShenandoahHeap::keep_alive(oop obj) { - if (is_concurrent_mark_in_progress() && (obj != nullptr)) { - ShenandoahBarrierSet::barrier_set()->enqueue(obj); - } + ShenandoahBarrierSet::barrier_set()->keepalive_barrier(ON_STRONG_OOP_REF, (oop*)nullptr, obj, ShenandoahBarrierSet::FILTER_MARKED); } void ShenandoahHeap::heap_region_iterate(ShenandoahHeapRegionClosure* blk) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 3bc0f050242f..835d141df950 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -26,6 +26,7 @@ #include "classfile/javaClasses.hpp" #include "gc/shared/workerThread.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" @@ -97,7 +98,7 @@ void set_oop_field(narrowOop* field, oop value) { static oop lrb(oop obj) { if (obj != nullptr && ShenandoahHeap::heap()->marking_context()->is_marked(obj)) { - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(obj); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, obj, (oop*)nullptr); } else { return obj; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 00910d3035ed..e921de34d1c9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -40,59 +40,59 @@ JRT_END JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre(oopDesc* obj)) // Called from barrier slow-paths on full buffer. // We need to enqueue without filters to force buffer cleanups. - ShenandoahBarrierSet::barrier_set()->enqueue(obj, /* filter = */ false); + ShenandoahBarrierSet::barrier_set()->keepalive_barrier(ON_STRONG_OOP_REF, (oop*)nullptr, obj, ShenandoahBarrierSet::FILTER_NONE); JRT_END JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre_narrow(narrowOop nobj)) assert(!CompressedOops::is_null(nobj), "Filtered by caller"); + oop obj = CompressedOops::decode_not_null(nobj); // Called from barrier slow-paths on full buffer. // We need to enqueue without filters to force buffer cleanups. - oop obj = CompressedOops::decode_not_null(nobj); - ShenandoahBarrierSet::barrier_set()->enqueue(obj, /* filter = */ false); + ShenandoahBarrierSet::barrier_set()->keepalive_barrier(ON_STRONG_OOP_REF, (oop*)nullptr, obj, ShenandoahBarrierSet::FILTER_NONE); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong(oopDesc* src, oop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong_narrow(oopDesc* src, narrowOop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, src, load_addr); JRT_END JRT_LEAF(narrowOop, ShenandoahRuntime::load_reference_barrier_strong_narrow_narrow(narrowOop src, narrowOop* load_addr)) assert(!CompressedOops::is_null(src), "Filtered by caller"); oop s = CompressedOops::decode_not_null(src); - oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(s, load_addr); + oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, s, load_addr); return CompressedOops::encode_not_null(r); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc* src, oop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak_narrow(oopDesc* src, narrowOop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, src, load_addr); JRT_END JRT_LEAF(narrowOop, ShenandoahRuntime::load_reference_barrier_weak_narrow_narrow(narrowOop src, narrowOop* load_addr)) assert(!CompressedOops::is_null(src), "Filtered by caller"); oop s = CompressedOops::decode_not_null(src); - oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(s, load_addr); + oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, s, load_addr); return CompressedOops::encode(r); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom(oopDesc* src, oop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom_narrow(oopDesc* src, narrowOop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, src, load_addr); JRT_END JRT_LEAF(narrowOop, ShenandoahRuntime::load_reference_barrier_phantom_narrow_narrow(narrowOop src, narrowOop* load_addr)) assert(!CompressedOops::is_null(src), "Filtered by caller"); oop s = CompressedOops::decode_not_null(src); - oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(s, load_addr); + oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, s, load_addr); return CompressedOops::encode(r); JRT_END diff --git a/src/hotspot/share/runtime/stackValue.cpp b/src/hotspot/share/runtime/stackValue.cpp index 8b613ff72801..fb91eb7e4c83 100644 --- a/src/hotspot/share/runtime/stackValue.cpp +++ b/src/hotspot/share/runtime/stackValue.cpp @@ -77,7 +77,7 @@ static oop oop_from_oop_location(stackChunkOop chunk, void* addr) { // stack values. Note: do not heal the location, to avoid accidentally // corrupting the stack. Stack watermark barriers are supposed to handle // the healing. - val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(val); + val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, val, (oop*)nullptr); } #endif @@ -114,7 +114,7 @@ static oop oop_from_narrowOop_location(stackChunkOop chunk, void* addr, bool is_ // stack values. Note: do not heal the location, to avoid accidentally // corrupting the stack. Stack watermark barriers are supposed to handle // the healing. - val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(val); + val = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_STRONG_OOP_REF, val, (narrowOop*)nullptr); } #endif From 66c21aec0e660028738dfeccacd855bd9594d269 Mon Sep 17 00:00:00 2001 From: Lijuan Li Date: Fri, 28 Aug 2026 09:21:37 +0000 Subject: [PATCH 127/223] 8391171: Enable TestVectorBroadcastTransforms.java IR tests for RISC-V Reviewed-by: fyang, dzhang, aivy --- .../TestVectorBroadcastTransforms.java | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java index be4aeef23e34..b09d71700509 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBroadcastTransforms.java @@ -55,7 +55,7 @@ public static void main(String[] args) { @Test @IR(failOn = IRNode.ADD_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_add(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -73,7 +73,7 @@ static void run_int_add() { @Test @IR(failOn = IRNode.SUB_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_sub(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -91,7 +91,7 @@ static void run_int_sub() { @Test @IR(failOn = IRNode.MUL_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_mul(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -107,11 +107,11 @@ static void run_int_mul() { Verify.checkEQ(ir, ia * ib); } - // Integer vector DIV is currently matched on SVE. push_through_replicate + // Integer vector DIV is currently matched on SVE and RVV. push_through_replicate // must be able to scalarize DivVI via VectorNode::make_scalar(Op_DivI). @Test @IR(failOn = IRNode.DIV_VI, - applyIfCPUFeature = {"sve", "true"}, + applyIfCPUFeatureOr = {"sve", "true", "rvv", "true"}, counts = { IRNode.DIV_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_div(int ia, int ib) { @@ -144,7 +144,7 @@ static void run_int_div_broadcast_constants() { @Test @IR(failOn = IRNode.AND_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.AND_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_and(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -162,7 +162,7 @@ static void run_int_and() { @Test @IR(failOn = IRNode.OR_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.OR_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_or(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -180,7 +180,7 @@ static void run_int_or() { @Test @IR(failOn = IRNode.XOR_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.XOR_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_xor(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -198,7 +198,7 @@ static void run_int_xor() { @Test @IR(failOn = IRNode.MIN_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MIN_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_min(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -216,7 +216,7 @@ static void run_int_min() { @Test @IR(failOn = IRNode.MAX_VI, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MAX_I, ">= 1", IRNode.REPLICATE_I, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static int int_max(int ia, int ib) { return IntVector.broadcast(ISP, ia) @@ -240,7 +240,7 @@ static void run_int_max() { @Test @IR(failOn = IRNode.ADD_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_add(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -258,7 +258,7 @@ static void run_long_add() { @Test @IR(failOn = IRNode.SUB_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_sub(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -276,7 +276,7 @@ static void run_long_sub() { @Test @IR(failOn = IRNode.MUL_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_mul(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -294,7 +294,7 @@ static void run_long_mul() { @Test @IR(failOn = IRNode.DIV_VL, - applyIfCPUFeature = {"sve", "true"}, + applyIfCPUFeatureOr = {"sve", "true", "rvv", "true"}, counts = { IRNode.DIV_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_div(long la, long lb) { @@ -314,7 +314,7 @@ static void run_long_div() { @Test @IR(failOn = IRNode.AND_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.AND_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_and(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -332,7 +332,7 @@ static void run_long_and() { @Test @IR(failOn = IRNode.OR_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.OR_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_or(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -350,7 +350,7 @@ static void run_long_or() { @Test @IR(failOn = IRNode.XOR_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.XOR_L, ">= 1", IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_xor(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -368,7 +368,7 @@ static void run_long_xor() { @Test @IR(failOn = IRNode.MIN_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = {IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_min(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -386,7 +386,7 @@ static void run_long_min() { @Test @IR(failOn = IRNode.MAX_VL, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = {IRNode.REPLICATE_L, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static long long_max(long la, long lb) { return LongVector.broadcast(LSP, la) @@ -410,7 +410,7 @@ static void run_long_max() { @Test @IR(failOn = IRNode.ADD_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_add(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -428,7 +428,7 @@ static void run_float_add() { @Test @IR(failOn = IRNode.SUB_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_sub(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -446,7 +446,7 @@ static void run_float_sub() { @Test @IR(failOn = IRNode.MUL_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_mul(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -464,7 +464,7 @@ static void run_float_mul() { @Test @IR(failOn = IRNode.DIV_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.DIV_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_div(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -483,7 +483,7 @@ static void run_float_div() { @Test @IR(failOn = IRNode.MIN_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MIN_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_min(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -501,7 +501,7 @@ static void run_float_min() { @Test @IR(failOn = IRNode.MAX_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MAX_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_max(float fa, float fb) { return FloatVector.broadcast(FSP, fa) @@ -519,7 +519,7 @@ static void run_float_max() { @Test @IR(failOn = IRNode.SQRT_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SQRT_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_sqrt(float fa) { return FloatVector.broadcast(FSP, fa) @@ -536,7 +536,7 @@ static void run_float_sqrt() { @Test @IR(failOn = IRNode.FMA_VF, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.FMA_F, ">= 1", IRNode.REPLICATE_F, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static float float_fma(float fa, float fb, float fc) { return FloatVector.broadcast(FSP, fa) @@ -562,7 +562,7 @@ static void run_float_fma() { @Test @IR(failOn = IRNode.ADD_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_add(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -580,7 +580,7 @@ static void run_double_add() { @Test @IR(failOn = IRNode.SUB_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_sub(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -598,7 +598,7 @@ static void run_double_sub() { @Test @IR(failOn = IRNode.MUL_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_mul(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -616,7 +616,7 @@ static void run_double_mul() { @Test @IR(failOn = IRNode.DIV_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.DIV_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_div(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -635,7 +635,7 @@ static void run_double_div() { @Test @IR(failOn = IRNode.MIN_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MIN_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_min(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -653,7 +653,7 @@ static void run_double_min() { @Test @IR(failOn = IRNode.MAX_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MAX_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_max(double da, double db) { return DoubleVector.broadcast(DSP, da) @@ -671,7 +671,7 @@ static void run_double_max() { @Test @IR(failOn = IRNode.SQRT_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SQRT_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_sqrt(double da) { return DoubleVector.broadcast(DSP, da) @@ -688,7 +688,7 @@ static void run_double_sqrt() { @Test @IR(failOn = IRNode.FMA_VD, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.FMA_D, ">= 1", IRNode.REPLICATE_D, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static double double_fma(double da, double db, double dc) { return DoubleVector.broadcast(DSP, da) @@ -716,7 +716,7 @@ static void run_double_fma() { @Test @IR(failOn = IRNode.ADD_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_add(byte ba, byte bb) { @@ -735,7 +735,7 @@ static void run_byte_add() { @Test @IR(failOn = IRNode.SUB_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_sub(byte ba, byte bb) { @@ -754,7 +754,7 @@ static void run_byte_sub() { @Test @IR(failOn = IRNode.ADD_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_add_overflow() { @@ -771,7 +771,7 @@ static void run_byte_add_overflow() { @Test @IR(failOn = IRNode.ADD_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_add_underflow() { @@ -788,7 +788,7 @@ static void run_byte_add_underflow() { @Test @IR(failOn = IRNode.SUB_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_sub_overflow() { @@ -805,7 +805,7 @@ static void run_byte_sub_overflow() { @Test @IR(failOn = IRNode.SUB_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_sub_underflow() { @@ -822,7 +822,7 @@ static void run_byte_sub_underflow() { @Test @IR(failOn = IRNode.MUL_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_mul(byte ba, byte bb) { @@ -841,7 +841,7 @@ static void run_byte_mul() { @Test @IR(failOn = IRNode.DIV_VB, - applyIfCPUFeature = {"sve", "true"}, + applyIfCPUFeatureOr = {"sve", "true", "rvv", "true"}, counts = { IRNode.DIV_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_div(byte ba, byte bb) { @@ -861,7 +861,7 @@ static void run_byte_div() { @Test @IR(failOn = IRNode.AND_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.AND_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_and(byte ba, byte bb) { return ByteVector.broadcast(BSP, ba) @@ -879,7 +879,7 @@ static void run_byte_and() { @Test @IR(failOn = IRNode.OR_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.OR_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_or(byte ba, byte bb) { return ByteVector.broadcast(BSP, ba) @@ -897,7 +897,7 @@ static void run_byte_or() { @Test @IR(failOn = IRNode.XOR_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.XOR_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_xor(byte ba, byte bb) { return ByteVector.broadcast(BSP, ba) @@ -915,7 +915,7 @@ static void run_byte_xor() { @Test @IR(failOn = IRNode.MIN_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MIN_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_min(byte ba, byte bb) { return ByteVector.broadcast(BSP, ba) @@ -933,7 +933,7 @@ static void run_byte_min() { @Test @IR(failOn = IRNode.MAX_VB, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MAX_I, ">= 1", IRNode.REPLICATE_B, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static byte byte_max(byte ba, byte bb) { return ByteVector.broadcast(BSP, ba) @@ -959,7 +959,7 @@ static void run_byte_max() { @Test @IR(failOn = IRNode.ADD_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_add(short sa, short sb) { @@ -978,7 +978,7 @@ static void run_short_add() { @Test @IR(failOn = IRNode.SUB_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_sub(short sa, short sb) { @@ -997,7 +997,7 @@ static void run_short_sub() { @Test @IR(failOn = IRNode.ADD_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_add_overflow() { @@ -1014,7 +1014,7 @@ static void run_short_add_overflow() { @Test @IR(failOn = IRNode.ADD_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.ADD_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_add_underflow() { @@ -1031,7 +1031,7 @@ static void run_short_add_underflow() { @Test @IR(failOn = IRNode.SUB_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_sub_overflow() { @@ -1048,7 +1048,7 @@ static void run_short_sub_overflow() { @Test @IR(failOn = IRNode.SUB_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.SUB_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_sub_underflow() { @@ -1065,7 +1065,7 @@ static void run_short_sub_underflow() { @Test @IR(failOn = IRNode.MUL_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MUL_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_mul(short sa, short sb) { @@ -1084,7 +1084,7 @@ static void run_short_mul() { @Test @IR(failOn = IRNode.DIV_VS, - applyIfCPUFeature = {"sve", "true"}, + applyIfCPUFeatureOr = {"sve", "true", "rvv", "true"}, counts = { IRNode.DIV_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_div(short sa, short sb) { @@ -1104,7 +1104,7 @@ static void run_short_div() { @Test @IR(failOn = IRNode.AND_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.AND_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_and(short sa, short sb) { return ShortVector.broadcast(SSP, sa) @@ -1122,7 +1122,7 @@ static void run_short_and() { @Test @IR(failOn = IRNode.OR_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.OR_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_or(short sa, short sb) { return ShortVector.broadcast(SSP, sa) @@ -1140,7 +1140,7 @@ static void run_short_or() { @Test @IR(failOn = IRNode.XOR_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.XOR_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_xor(short sa, short sb) { return ShortVector.broadcast(SSP, sa) @@ -1158,7 +1158,7 @@ static void run_short_xor() { @Test @IR(failOn = IRNode.MIN_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MIN_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_min(short sa, short sb) { return ShortVector.broadcast(SSP, sa) @@ -1176,7 +1176,7 @@ static void run_short_min() { @Test @IR(failOn = IRNode.MAX_VS, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, counts = { IRNode.MAX_I, ">= 1", IRNode.REPLICATE_S, IRNode.VECTOR_SIZE_ANY, ">= 1" }) static short short_max(short sa, short sb) { return ShortVector.broadcast(SSP, sa) From d398b221044e5fe7a0eccf32632da2839b863f32 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 28 Aug 2026 09:28:07 +0000 Subject: [PATCH 128/223] 8391178: TypeAryPtr::narrow_size_type returns incorrect type for flat arrays Reviewed-by: qamai, mchevalier --- src/hotspot/share/opto/graphKit.cpp | 3 +- src/hotspot/share/opto/type.cpp | 27 +++--- src/hotspot/share/opto/type.hpp | 2 +- .../arrays/TestFlatArrayMaximumLength.java | 87 +++++++++++++++++++ 4 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 test/hotspot/jtreg/resourcehogs/compiler/arrays/TestFlatArrayMaximumLength.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index eb81eb18ba8f..27d7f76e02fa 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4659,8 +4659,7 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) Node* valid_length_test = _gvn.intcon(1); if (ary_type->isa_aryptr()) { - BasicType bt = ary_type->isa_aryptr()->elem()->array_element_basic_type(); - jint max = TypeAryPtr::max_array_length(bt); + jint max = ary_type->is_aryptr()->max_array_length(); Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max))); valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le)); } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 7f39d1de985b..532ccc929964 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -4697,17 +4697,24 @@ const TypeAryPtr* TypeAryPtr::cast_to_instance_id(int instance_id) const { //-----------------------------max_array_length------------------------------- // A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization. -jint TypeAryPtr::max_array_length(BasicType etype) { - if (!is_java_primitive(etype) && !::is_reference_type(etype)) { - if (etype == T_NARROWOOP) { - etype = T_OBJECT; - } else if (etype == T_ILLEGAL) { // bottom[] - etype = T_BYTE; // will produce conservatively high value - } else { - fatal("not an element type: %s", type2name(etype)); +jint TypeAryPtr::max_array_length() const { + if (is_not_flat()) { + BasicType etype = elem()->array_element_basic_type(); + if (!is_java_primitive(etype) && !::is_reference_type(etype)) { + if (etype == T_NARROWOOP) { + etype = T_OBJECT; + } else if (etype == T_ILLEGAL) { // bottom[] + etype = T_BYTE; // will produce conservatively high value + } else { + fatal("not an element type: %s", type2name(etype)); + } } + return arrayOopDesc::max_array_length(etype); + } else { + // A flat array's maximum length depends on its layout. If the layout + // is not known, max_jint is the only conservative upper bound. + return is_flat() && klass_is_exact() ? max_flat_elements() : max_jint; } - return arrayOopDesc::max_array_length(etype); } //-----------------------------narrow_size_type------------------------------- @@ -4717,7 +4724,7 @@ const TypeInt* TypeAryPtr::narrow_size_type(const TypeInt* size) const { jint hi = size->_hi; jint lo = size->_lo; jint min_lo = 0; - jint max_hi = max_array_length(elem()->array_element_basic_type()); + jint max_hi = max_array_length(); //if (index_not_size) --max_hi; // type of a valid array index, FTR bool chg = false; if (lo < min_lo) { diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 15587dc740e7..40eacfb9b182 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1818,7 +1818,7 @@ class TypeAryPtr : public TypeOopPtr { const TypeAryPtr* cast_to_autobox_cache() const; - static jint max_array_length(BasicType etype); + jint max_array_length() const; int flat_offset() const; const Offset field_offset() const { return _field_offset; } diff --git a/test/hotspot/jtreg/resourcehogs/compiler/arrays/TestFlatArrayMaximumLength.java b/test/hotspot/jtreg/resourcehogs/compiler/arrays/TestFlatArrayMaximumLength.java new file mode 100644 index 000000000000..2569c788c183 --- /dev/null +++ b/test/hotspot/jtreg/resourcehogs/compiler/arrays/TestFlatArrayMaximumLength.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arrays; + +/** + * @test + * @bug 8391178 + * @summary Test correctness of C2's type for the length of large flat arrays + * @enablePreview + * @requires vm.compiler2.enabled & os.maxMemory > 4G + * @run main/othervm -Xmx4g -Xcomp -XX:-TieredCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + */ +public class TestFlatArrayMaximumLength { + + static value class EmptyValue { } + static final int[] smallArray = new int[2]; + static EmptyValue[] largeArray; + + static int test1() { + // C2 must preserve the normal return from this legal allocation + EmptyValue[] array = new EmptyValue[Integer.MAX_VALUE]; + largeArray = array; + return array.length; + } + + static void test2(int length) { + // The type of array.length is set to [0..Integer.MAX_VALUE-2] + // while it should be [0..Integer.MAX_VALUE] for a flat array. + EmptyValue[] array = new EmptyValue[length]; + // The range of index is therefore [0..1] but should be [0..2]. + int index = (array.length + 2) >>> 30; + // The range of index is still [0..1] but should be [0..4] now. + index = index * index; + // The range check will be removed here because [0..1] is always + // in range but that's incorrect because [0..4] is not in range. + // With length == Integer.MAX_VALUE, index is 4 and we fail to + // throw an exception and write beyond the end of the array. + smallArray[index] = 42; + } + + public static void main(String[] args) { + // Make sure that class is loaded + EmptyValue tmp = new EmptyValue(); + + if (test1() != Integer.MAX_VALUE) { + throw new RuntimeException("Incorrect array length"); + } + largeArray = null; + System.gc(); + + for (int i = 0; i < 30_000; i++) { + test2(1); + } + + try { + test2(Integer.MAX_VALUE); + throw new RuntimeException("No IndexOutOfBoundsException thrown!"); + } catch (IndexOutOfBoundsException expected) { + // Expected + } + } +} + From 1d173df7c110c3750a52a09146a5d05ef0fa2938 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 28 Aug 2026 09:36:32 +0000 Subject: [PATCH 129/223] 8391174: Simplify `identity_hash` after UseObjectMonitorTable removal Reviewed-by: stefank, jsjolen, iklam --- src/hotspot/share/cds/aotMappedHeapWriter.cpp | 35 ++++++------------- .../share/cds/aotStreamedHeapWriter.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 2 +- src/hotspot/share/oops/markWord.cpp | 6 ++-- src/hotspot/share/oops/markWord.hpp | 15 +++++--- src/hotspot/share/oops/oop.cpp | 28 ++++++++++++--- src/hotspot/share/oops/oop.hpp | 9 +++-- src/hotspot/share/oops/oop.inline.hpp | 20 +++++------ src/hotspot/share/prims/jvm.cpp | 4 +-- src/hotspot/share/prims/jvmtiTagMapTable.cpp | 10 +++--- src/hotspot/share/runtime/synchronizer.cpp | 32 +++-------------- src/hotspot/share/runtime/synchronizer.hpp | 4 +-- .../share/services/finalizerService.cpp | 4 +-- test/hotspot/gtest/oops/test_markWord.cpp | 14 ++++---- 14 files changed, 84 insertions(+), 101 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index cfa6c460303e..8db7c6f3ff2d 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -725,39 +725,26 @@ template void AOTMappedHeapWriter::mark_oop_pointer(T* buffered_add oopmap->set_bit(idx); } -void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass) { +void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass) { narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass); address buffered_addr = requested_addr_to_buffered_addr(cast_from_oop
      (requested_obj)); - oop fake_oop = cast_to_oop(buffered_addr); - if (UseCompactObjectHeaders) { - markWord prototype_header = src_klass->prototype_header().set_narrow_klass(nk); - fake_oop->set_mark(prototype_header); - } else { - fake_oop->set_narrow_klass(nk); - } + markWord mw = Arguments::is_valhalla_enabled() ? src_klass->prototype_header() : markWord::prototype(); + oopDesc* fake_oop = (oopDesc*)buffered_addr; - if (src_obj == nullptr) { - return; - } // We need to retain the identity_hash, because it may have been used by some hashtables // in the shared heap. - if (!src_obj->fast_no_hash_check() && (!(Arguments::is_valhalla_enabled() && src_obj->mark().is_inline_type()))) { + if (src_obj != nullptr && !src_obj->is_inline_type() && src_obj->has_identity_hash()) { intptr_t src_hash = src_obj->identity_hash(); - if (UseCompactObjectHeaders) { - fake_oop->set_mark(fake_oop->mark().copy_set_hash(src_hash)); - } else if (Arguments::is_valhalla_enabled()) { - fake_oop->set_mark(src_klass->prototype_header().copy_set_hash(src_hash)); - } else { - fake_oop->set_mark(markWord::prototype().copy_set_hash(src_hash)); - } - assert(fake_oop->mark().is_unlocked(), "sanity"); + mw = mw.copy_set_hash(src_hash); + } - DEBUG_ONLY(intptr_t archived_hash = fake_oop->identity_hash()); - assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash); + if (UseCompactObjectHeaders) { + fake_oop->set_mark(mw.set_narrow_klass(nk)); + } else { + fake_oop->set_mark(mw); + fake_oop->set_narrow_klass(nk); } - // Strip age bits. - fake_oop->set_mark(fake_oop->mark().set_age(0)); } class AOTMappedHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure { diff --git a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp index 8009e63e63d0..a8a5a5beb380 100644 --- a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp @@ -371,7 +371,7 @@ template void AOTStreamedHeapWriter::map_oop_field_in_buffer(oop ob void AOTStreamedHeapWriter::update_header_for_buffered_addr(address buffered_addr, oop src_obj, Klass* src_klass) { narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass); - markWord mw = Arguments::enable_preview() ? src_klass->prototype_header() : markWord::prototype(); + markWord mw = Arguments::is_valhalla_enabled() ? src_klass->prototype_header() : markWord::prototype(); oopDesc* fake_oop = (oopDesc*)buffered_addr; // We need to retain the identity_hash, because it may have been used by some hashtables diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 93d9061efb98..f94582c8a51f 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -909,7 +909,7 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) { void HeapShared::copy_java_mirror(oop orig_mirror, oop scratch_m) { // We need to retain the identity_hash, because it may have been used by some hashtables // in the shared heap. - if (!orig_mirror->fast_no_hash_check()) { + if (orig_mirror->has_identity_hash()) { intptr_t src_hash = orig_mirror->identity_hash(); if (UseCompactObjectHeaders) { narrowKlass nk = CompressedKlassPointers::encode(orig_mirror->klass()); diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index e1220583c429..7bd55e064b04 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -48,10 +48,10 @@ void markWord::print_on(outputStream* st) const { if (is_inline_type()) { st->print(" inline_type"); } - if (has_no_hash()) { - st->print(" no_hash"); - } else { + if (has_hash()) { st->print(" hash=" INTPTR_FORMAT, hash()); + } else { + st->print(" no_hash"); } #ifdef _LP64 // 64 bit encodings have array information // flat or null-free do not imply each other diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 63bcd27c3397..b2bd5d89e502 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -73,9 +73,12 @@ // * null-free arrays: An array instance without null elements // * valhalla reserved: Reserved for future use // -// Inline types cannot be locked and do not have an identity hash. +// Inline types cannot be locked. // -// - hash - contains the identity hash value: largest value is 31 bits, see +// Inline types have a deterministic hash based on the immutable payload +// and class, which may be cached in the markWord. +// +// - hash - contains the hash value: largest value is 31 bits, see // os::random(). Also, 64-bit VMs require a hash value no bigger than 32 // bits because they will not properly generate a mask larger than that: // see library_call.cpp @@ -228,7 +231,7 @@ class markWord { // The reserved bits are only guaranteed to be unset if the mark word is "unlocked" LP64_ONLY(assert(!is_unlocked() || mask_bits(value(), valhalla_reserved_bit_in_place) == 0, "Reserved bits should not be used. _value: " PTR_FORMAT, _value)); - return !is_unlocked() || !has_no_hash(); + return !is_unlocked() || has_hash(); } // WARNING: The following routines are used EXCLUSIVELY by @@ -269,11 +272,13 @@ class markWord { // hash operations intptr_t hash() const { + precond(!is_marked()); return mask_bits(value() >> hash_shift, hash_mask); } - bool has_no_hash() const { - return hash() == no_hash; + bool has_hash() const { + precond(!is_marked()); + return hash() != no_hash; } bool is_flat_array() const { diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index a9900bf1509c..4a7c7ad688d1 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -115,10 +115,30 @@ void oopDesc::verify(oopDesc* oop_desc) { verify_on(tty, oop_desc); } -intptr_t oopDesc::slow_identity_hash() { - // slow case; we have to acquire the micro lock in order to locate the header - Thread* current = Thread::current(); - return ObjectSynchronizer::FastHashCode(current, this); +intptr_t oopDesc::slow_identity_hash(markWord current_mark, Thread* current) { + precond(!current_mark.has_hash()); + + assert(!is_inline(), "slow_identity_hash should not be called for value objects"); + + // Calculate the new hash + const intptr_t new_hash = ObjectSynchronizer::get_next_hash(current, this); + + markWord mark = current_mark; + while (true) { + const markWord old_mark = mark; + const markWord new_mark = mark.copy_set_hash(new_hash); + + // Try to install the hash + mark = cas_set_mark(new_mark, old_mark, memory_order_relaxed); + if (old_mark == mark) { + // CAS succeded, return the installed hash + return new_hash; + } else if (mark.has_hash()) { + // Another thread installed a hash, return the installed hash + return mark.hash(); + } + // CAS failed, retry + } } // used only for asserts and guarantees diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 0b2e2aa49d20..6675c4f49edf 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -316,10 +316,13 @@ class oopDesc { inline static bool is_instanceof_or_null(oop obj, Klass* klass); // identity hash; returns the identity hash key (computes it if necessary) - inline intptr_t identity_hash(); - intptr_t slow_identity_hash(); - inline bool fast_no_hash_check(); + inline intptr_t identity_hash(Thread* current = nullptr); + inline bool has_identity_hash(); +private: + intptr_t slow_identity_hash(markWord current_mark, Thread* current); + +public: // Checks if the mark word needs to be preserved inline bool mark_must_be_preserved() const; inline bool mark_must_be_preserved(markWord m) const; diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index fb4309049cb3..04176d04b3da 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -404,25 +404,21 @@ bool oopDesc::is_instanceof_or_null(oop obj, Klass* klass) { return obj == nullptr || obj->klass()->is_subtype_of(klass); } -intptr_t oopDesc::identity_hash() { - // Fast case; if the object is unlocked and the hash value is set, no locking is needed +intptr_t oopDesc::identity_hash(Thread* current) { // Note: The mark must be read into local variable to avoid concurrent updates. markWord mrk = mark(); - if (mrk.is_unlocked() && !mrk.has_no_hash()) { - return mrk.hash(); - } else if (mrk.is_marked()) { + assert(!mrk.is_marked(), "should never be marked"); + + if (mrk.has_hash()) { return mrk.hash(); - } else { - return slow_identity_hash(); } + + return slow_identity_hash(mrk, current == nullptr ? Thread::current() : current); } -// This checks fast simple case of whether the oop has_no_hash, -// to optimize JVMTI table lookup. -bool oopDesc::fast_no_hash_check() { +bool oopDesc::has_identity_hash() { markWord mrk = mark_acquire(); - assert(!mrk.is_marked(), "should never be marked"); - return mrk.is_unlocked() && mrk.has_no_hash(); + return mrk.has_hash(); } bool oopDesc::mark_must_be_preserved() const { diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index bf4fc4b961a0..da92cffe5c7b 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -826,7 +826,7 @@ JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) current_mark = ho->mark(); new_mark = current_mark.copy_set_hash(identity_hash); old_mark = ho->cas_set_mark(new_mark, current_mark); - assert(old_mark.has_no_hash() || old_mark.hash() == new_mark.hash(), + assert(!old_mark.has_hash() || old_mark.hash() == new_mark.hash(), "CAS identity hash invariant violated, expected=" INTPTR_FORMAT " actual=" INTPTR_FORMAT, new_mark.hash(), old_mark.hash()); @@ -834,7 +834,7 @@ JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) return checked_cast(new_mark.hash()); } else { - return checked_cast(ObjectSynchronizer::FastHashCode(THREAD, obj)); + return checked_cast(obj->identity_hash(THREAD)); } JVM_END diff --git a/src/hotspot/share/prims/jvmtiTagMapTable.cpp b/src/hotspot/share/prims/jvmtiTagMapTable.cpp index f16bd79d2174..c1992e308ce8 100644 --- a/src/hotspot/share/prims/jvmtiTagMapTable.cpp +++ b/src/hotspot/share/prims/jvmtiTagMapTable.cpp @@ -244,11 +244,9 @@ jlong* JvmtiTagMapTable::lookup(const JvmtiHeapwalkObject& obj) const { return nullptr; } - if (!obj.is_value()) { - if (obj.obj()->fast_no_hash_check()) { - // Objects in the table all have a hashcode, unless inlined types. - return nullptr; - } + if (!obj.is_value() && !obj.obj()->has_identity_hash()) { + // Objects in the table all have a hashcode, unless inlined types. + return nullptr; } JvmtiTagMapKey entry(&obj); jlong* found = _table.get(entry); @@ -265,7 +263,7 @@ void JvmtiTagMapTable::add(const JvmtiHeapwalkObject& obj, jlong tag) { assert(!obj.is_flat(), "Cannot add flat object to JvmtiTagMapTable"); JvmtiTagMapKey new_entry(&obj); bool is_added; - if (!obj.is_value() && obj.obj()->fast_no_hash_check()) { + if (!obj.is_value() && !obj.obj()->has_identity_hash()) { // Can't be in the table so add it fast. is_added = _table.put_when_absent(new_entry, tag); } else { diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index d05f1d3e9c26..7a20af676c6d 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -635,7 +635,7 @@ static SharedGlobals GVars; // There are simple ways to "diffuse" the middle address bits over the // generated hashCode values: -static intptr_t get_next_hash(Thread* current, oop obj) { +intptr_t ObjectSynchronizer::get_next_hash(Thread* current, oop obj) { intptr_t value = 0; if (hashCode == 0) { // This form uses global Park-Miller RNG. @@ -675,30 +675,6 @@ static intptr_t get_next_hash(Thread* current, oop obj) { return value; } -intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { - // VM should be calling bootstrap method. - assert(!obj->klass()->is_inline_klass(), "FastHashCode should not be called for inline classes"); - - while (true) { - markWord temp, test; - intptr_t hash; - markWord mark = obj->mark_acquire(); - // The hash is located in the object header. - hash = mark.hash(); - if (hash != 0) { // if it has a hash, just return it - return hash; - } - hash = get_next_hash(current, obj); // get a new hash - temp = mark.copy_set_hash(hash); // merge the hash into header - // try to install the hash - test = obj->cas_set_mark(temp, mark); - if (test == mark) { // if the hash was installed, return it - return hash; - } - // CAS failed, retry - } -} - bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, Handle h_obj) { if (h_obj->mark().is_inline_type()) { @@ -1506,7 +1482,7 @@ void ObjectSynchronizer::remove_monitor(ObjectMonitor* monitor, oop obj) { void ObjectSynchronizer::deflate_mark_word(oop obj) { markWord mark = obj->mark_acquire(); - assert(!mark.has_no_hash(), "obj with inflated monitor must have had a hash"); + assert(mark.has_hash(), "obj with inflated monitor must have had a hash"); while (mark.has_monitor()) { const markWord new_mark = mark.clear_lock_bits().set_unlocked(); @@ -1887,7 +1863,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_fast_locked_object(oop object, Object ObjectMonitor* monitor; // Inflating requires a hash code - ObjectSynchronizer::FastHashCode(current, object); + (void)object->identity_hash(current); markWord mark = object->mark_acquire(); assert(!mark.is_unlocked(), "Cannot be unlocked"); @@ -1952,7 +1928,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_and_enter(oop object, BasicLock* lock // Get or create the monitor if (monitor == nullptr) { // Lightweight monitors require that hash codes are installed first - ObjectSynchronizer::FastHashCode(locking_thread, object); + (void)object->identity_hash(locking_thread); monitor = get_or_insert_monitor(object, current, cause); } diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 66588e82bcd2..adbb86eb859e 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -127,9 +127,7 @@ class ObjectSynchronizer : AllStatic { static ObjectMonitor* read_monitor(oop obj); - // Returns the identity hash value for an oop - // NOTE: It may cause monitor inflation - static intptr_t FastHashCode(Thread* current, oop obj); + static intptr_t get_next_hash(Thread* current, oop obj); // java.lang.Thread support static bool current_thread_holds_lock(JavaThread* current, Handle h_obj); diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index d57d0fb5b50c..6d78ca1e9786 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -299,7 +299,7 @@ static FinalizerEntry* get_entry(oop finalizee, Thread* thread) { static void log_registered(oop finalizee, Thread* thread) { ResourceMark rm(thread); - const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee); + const intptr_t identity_hash = finalizee->identity_hash(thread); log_info(finalizer)("Registered object (" INTPTR_FORMAT ") of class %s as finalizable", identity_hash, finalizee->klass()->external_name()); } @@ -314,7 +314,7 @@ void FinalizerService::on_register(oop finalizee, Thread* thread) { static void log_completed(oop finalizee, Thread* thread) { ResourceMark rm(thread); - const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee); + const intptr_t identity_hash = finalizee->identity_hash(thread); log_info(finalizer)("Finalizer was run for object (" INTPTR_FORMAT ") of class %s", identity_hash, finalizee->klass()->external_name()); } diff --git a/test/hotspot/gtest/oops/test_markWord.cpp b/test/hotspot/gtest/oops/test_markWord.cpp index 29f16f0753fd..4e322b53d445 100644 --- a/test/hotspot/gtest/oops/test_markWord.cpp +++ b/test/hotspot/gtest/oops/test_markWord.cpp @@ -123,10 +123,10 @@ static void assert_unlocked_state(markWord mark) { static void assert_copy_set_hash(markWord mark) { const intptr_t hash = 4711; - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); markWord copy = mark.copy_set_hash(hash); EXPECT_EQ(hash, copy.hash()); - EXPECT_FALSE(copy.has_no_hash()); + EXPECT_TRUE(copy.has_hash()); } static void assert_type(markWord mark) { @@ -141,7 +141,7 @@ TEST_VM(markWord, prototype) { assert_type(mark); - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); assert_copy_set_hash(mark); @@ -162,7 +162,7 @@ TEST_VM(markWord, inline_type_prototype) { assert_inline_type(mark); - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); } @@ -181,7 +181,7 @@ TEST_VM(markWord, null_free_flat_array_prototype) { assert_flat_array_type(mark); EXPECT_TRUE(mark.is_null_free_array()); - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); assert_copy_set_hash(mark); @@ -199,7 +199,7 @@ TEST_VM(markWord, nullable_flat_array_prototype) { assert_flat_array_type(mark); EXPECT_FALSE(mark.is_null_free_array()); - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); assert_copy_set_hash(mark); @@ -222,7 +222,7 @@ TEST_VM(markWord, null_free_array_prototype) { assert_null_free_array_type(mark); - EXPECT_TRUE(mark.has_no_hash()); + EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); assert_copy_set_hash(mark); From 31f4e4372f730f9f01bfbe752aa9abac5e3e9838 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 28 Aug 2026 09:54:54 +0000 Subject: [PATCH 130/223] 8390661: gc/TestGCALotAtSafepoints sub-tests times out Reviewed-by: aboldtch, coleenp, ayang --- src/hotspot/share/runtime/java.cpp | 6 +++++ src/hotspot/share/runtime/javaThread.cpp | 4 +-- src/hotspot/share/runtime/javaThread.hpp | 2 +- src/hotspot/share/runtime/mutex.cpp | 17 +++++++----- src/hotspot/share/runtime/mutex.hpp | 2 +- src/hotspot/share/runtime/thread.hpp | 24 +++++++++++++++++ src/hotspot/share/runtime/vmThread.cpp | 27 +------------------ test/hotspot/jtreg/ProblemList.txt | 5 ---- .../jtreg/gc/TestGCALotAtAllSafepoints.java | 7 ++++- 9 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 8578dd171ee8..084269a530c5 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -380,6 +380,12 @@ void before_exit(JavaThread* thread, bool halt) { Events::log(thread, "Before exit entered"); + // A GC requested after we shut down the heap blocks that requesting Java thread. + // Suppress GC-a-lot for threads entering shutdown as Monitor::lock() calls in the + // remainder of the shutdown sequence could otherwise block when executing a + // GC-a-lot caused collection. + NOT_PRODUCT(thread->set_skip_gcalot(true);) + // Note: don't use a Mutex to guard the entire before_exit(), as // JVMTI post_thread_end_event and post_vm_death_event will run native code. // A CAS or OSMutex would work just fine but then we need to manipulate diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index fc593b7f4364..c14126b6c5dc 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -281,7 +281,7 @@ void JavaThread::check_possible_safepoint() { #endif // CHECK_UNHANDLED_OOPS } -void JavaThread::check_for_valid_safepoint_state(bool allow_gcalot) { +void JavaThread::check_for_valid_safepoint_state() { // Don't complain if running a debugging command. if (DebuggingContext::is_enabled()) return; @@ -294,7 +294,7 @@ void JavaThread::check_for_valid_safepoint_state(bool allow_gcalot) { fatal("LEAF method calling lock?"); } - if (GCALotAtAllSafepoints && allow_gcalot) { + if (GCALotAtAllSafepoints) { // We could enter a safepoint here and thus have a gc InterfaceSupport::check_gc_alot(); } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index b08a4e6da007..8418b62b1fec 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -284,7 +284,7 @@ class JavaThread: public Thread { public: // These functions check conditions before possibly going to a safepoint. // including NoSafepointVerifier. - void check_for_valid_safepoint_state(bool allow_gcalot = true) NOT_DEBUG_RETURN; + void check_for_valid_safepoint_state() NOT_DEBUG_RETURN; void check_possible_safepoint() NOT_DEBUG_RETURN; #ifdef ASSERT diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index 9f3be83b3e0b..6627b4e4b6b8 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -61,7 +61,7 @@ void Mutex::check_block_state(Thread* thread) { "locking not allowed when crash protection is set"); } -void Mutex::check_safepoint_state(Thread* thread, bool allow_gcalot) { +void Mutex::check_safepoint_state(Thread* thread) { check_block_state(thread); // If the lock acquisition checks for safepoint, verify that the lock was created with rank that @@ -72,7 +72,7 @@ void Mutex::check_safepoint_state(Thread* thread, bool allow_gcalot) { if (thread->is_active_Java_thread()) { // Also check NoSafepointVerifier, and thread state is _thread_in_vm - JavaThread::cast(thread)->check_for_valid_safepoint_state(allow_gcalot); + JavaThread::cast(thread)->check_for_valid_safepoint_state(); } } @@ -116,7 +116,7 @@ void Mutex::lock_contended(Thread* self) { void Mutex::lock(Thread* self) { assert(owner() != self, "invariant"); - check_safepoint_state(self, true /* allow_gcalot */); + check_safepoint_state(self); check_rank(self); OrderAccess::fence(); @@ -246,10 +246,13 @@ bool Monitor::wait(uint64_t timeout) { // Check safepoint state after resetting owner and possible NSV. // Although the (HotSpot) monitor is logically released, the underlying - // OS monitor is still held. If this is the Heap_lock we would - // deadlock in the GC prologue trying to acquire the lock recursively. - // Suppress GC-a-lot in that case. - check_safepoint_state(self, this != Heap_lock); + // OS monitor is still held. Do not execute GC-a-lot here because + // garbage collection may (in)directly require the current monitor to + // progress. + { + SkipGCALot sgcalot(self); + check_safepoint_state(self); + } int wait_status; InFlightMutexRelease ifmr(this); diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index e497fbb34585..4d30a320cbf8 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -141,7 +141,7 @@ class Mutex : public CHeapObj { protected: void set_owner_implementation(Thread* owner) NOT_DEBUG({ raw_set_owner(owner);}); void check_block_state (Thread* thread) NOT_DEBUG_RETURN; - void check_safepoint_state (Thread* thread, bool allow_gcalot) NOT_DEBUG_RETURN; + void check_safepoint_state (Thread* thread) NOT_DEBUG_RETURN; void check_no_safepoint_state(Thread* thread) NOT_DEBUG_RETURN; void check_rank (Thread* thread) NOT_DEBUG_RETURN; void assert_owner (Thread* expected) NOT_DEBUG_RETURN; diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 8ebedb79bfc6..5b0f53f2189c 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -667,4 +667,28 @@ inline Thread* Thread::current_or_null_safe() { return nullptr; } +// A SkipGCALot object is used to elide the usual effect of gc-a-lot +// over a section of execution by a thread. +class SkipGCALot : public StackObj { + private: + bool _saved; + Thread* _t; + + public: +#ifdef ASSERT + SkipGCALot(Thread* t) : _t(t) { + _saved = _t->skip_gcalot(); + _t->set_skip_gcalot(true); + } + + ~SkipGCALot() { + assert(_t->skip_gcalot(), "Save-restore protocol invariant"); + _t->set_skip_gcalot(_saved); + } +#else + SkipGCALot(Thread* t) { } + ~SkipGCALot() { } +#endif +}; + #endif // SHARE_RUNTIME_THREAD_HPP diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 260b0f6f0433..505b53f5909f 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -488,31 +488,6 @@ void VMThread::loop() { } } -// A SkipGCALot object is used to elide the usual effect of gc-a-lot -// over a section of execution by a thread. Currently, it's used only to -// prevent re-entrant calls to GC. -class SkipGCALot : public StackObj { - private: - bool _saved; - Thread* _t; - - public: -#ifdef ASSERT - SkipGCALot(Thread* t) : _t(t) { - _saved = _t->skip_gcalot(); - _t->set_skip_gcalot(true); - } - - ~SkipGCALot() { - assert(_t->skip_gcalot(), "Save-restore protocol invariant"); - _t->set_skip_gcalot(_saved); - } -#else - SkipGCALot(Thread* t) { } - ~SkipGCALot() { } -#endif -}; - void VMThread::execute(VM_Operation* op) { Thread* t = Thread::current(); diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a4308c7ea301..59bbb43c379b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -87,11 +87,6 @@ gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#generational 83869 gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#default 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#generational 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#default 8386964 generic-all -gc/TestGCALotAtAllSafepoints.java#Parallel 8390661 generic-all -gc/TestGCALotAtAllSafepoints.java#Serial 8390661 generic-all -gc/TestGCALotAtAllSafepoints.java#G1 8390661 generic-all -gc/TestGCALotAtAllSafepoints.java#Z 8390661 generic-all -gc/TestGCALotAtAllSafepoints.java#Shenandoah 8390661 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/gc/TestGCALotAtAllSafepoints.java b/test/hotspot/jtreg/gc/TestGCALotAtAllSafepoints.java index 76a0482322a9..fa03d7341c13 100644 --- a/test/hotspot/jtreg/gc/TestGCALotAtAllSafepoints.java +++ b/test/hotspot/jtreg/gc/TestGCALotAtAllSafepoints.java @@ -100,10 +100,15 @@ public class TestGCALotAtAllSafepoints { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args[0], "-Xmx16m", + // Even this small test can generate thousands of GCs. Reduce them. + "-XX:ScavengeALotInterval=13", "-XX:+GCALotAtAllSafepoints", "-XX:+ScavengeALot", + "-Xlog:gc,gc+start,safepoint", "NoSuchClass"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + Process process = ProcessTools.startProcess("gcalot", pb); + OutputAnalyzer output = new OutputAnalyzer(process); output.shouldMatch("Error: Could not find or load main class NoSuchClass"); output.shouldHaveExitValue(1); } From 7c06964cfd5dd0a063b4bc07089512b7b658796f Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 28 Aug 2026 09:59:53 +0000 Subject: [PATCH 131/223] 8390935: G1: Retained regions do not get an efficiency assigned Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index ac1b29a6bd79..bf3372023b11 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -345,6 +345,7 @@ void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) { G1CSetCandidateGroup* gr = new G1CSetCandidateGroup(); gr->add(r); + gr->calculate_efficiency(); _retained_groups.append(gr); } From 9096e2917a410f0964c5e788ee393b946f5a23ab Mon Sep 17 00:00:00 2001 From: David Briemann Date: Fri, 28 Aug 2026 11:06:29 +0000 Subject: [PATCH 132/223] 8385696: Remove unnecessary ICache flush calls before code copy operations Reviewed-by: mdoerr, amitkumar, kvn, fyang --- .../cpu/aarch64/downcallLinker_aarch64.cpp | 2 +- .../cpu/aarch64/interpreterRT_aarch64.cpp | 4 ++-- .../cpu/aarch64/jniFastGetField_aarch64.cpp | 4 ++-- src/hotspot/cpu/aarch64/runtime_aarch64.cpp | 10 +++------ .../cpu/aarch64/sharedRuntime_aarch64.cpp | 22 +++++++------------ .../cpu/aarch64/upcallLinker_aarch64.cpp | 4 ++-- .../cpu/aarch64/vtableStubs_aarch64.cpp | 6 ++--- src/hotspot/cpu/arm/jniFastGetField_arm.cpp | 4 ++-- src/hotspot/cpu/arm/macroAssembler_arm.hpp | 2 +- src/hotspot/cpu/arm/runtime_arm.cpp | 6 ++--- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 10 ++++----- src/hotspot/cpu/arm/vtableStubs_arm.cpp | 4 ++-- src/hotspot/cpu/ppc/assembler_ppc.hpp | 4 ---- src/hotspot/cpu/ppc/downcallLinker_ppc.cpp | 4 ++-- src/hotspot/cpu/ppc/interpreterRT_ppc.cpp | 6 ++--- src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp | 2 +- src/hotspot/cpu/ppc/runtime_ppc.cpp | 7 +++--- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 18 ++++++--------- .../ppc/templateInterpreterGenerator_ppc.cpp | 6 ++--- src/hotspot/cpu/ppc/upcallLinker_ppc.cpp | 6 ++--- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 4 ++-- src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp | 6 ++--- .../cpu/riscv/downcallLinker_riscv.cpp | 2 +- src/hotspot/cpu/riscv/interpreterRT_riscv.cpp | 4 ++-- .../cpu/riscv/jniFastGetField_riscv.cpp | 2 +- src/hotspot/cpu/riscv/runtime_riscv.cpp | 8 +++---- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 16 +++++--------- src/hotspot/cpu/riscv/upcallLinker_riscv.cpp | 4 ++-- src/hotspot/cpu/riscv/vtableStubs_riscv.cpp | 4 ++-- src/hotspot/cpu/s390/downcallLinker_s390.cpp | 2 +- src/hotspot/cpu/s390/interpreterRT_s390.cpp | 6 ++--- src/hotspot/cpu/s390/jniFastGetField_s390.cpp | 6 ++--- src/hotspot/cpu/s390/runtime_s390.cpp | 7 +++--- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 19 +++++++--------- src/hotspot/cpu/s390/upcallLinker_s390.cpp | 2 +- src/hotspot/cpu/s390/vm_version_s390.cpp | 4 ++-- src/hotspot/cpu/s390/vtableStubs_s390.cpp | 6 ++--- src/hotspot/cpu/x86/downcallLinker_x86_64.cpp | 2 +- src/hotspot/cpu/x86/icache_x86.hpp | 12 +--------- src/hotspot/cpu/x86/interpreterRT_x86_64.cpp | 4 ++-- .../cpu/x86/jniFastGetField_x86_64.cpp | 6 ++--- src/hotspot/cpu/x86/runtime_x86_64.cpp | 8 +++---- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 22 +++++++------------ src/hotspot/cpu/x86/upcallLinker_x86_64.cpp | 4 ++-- src/hotspot/cpu/x86/vtableStubs_x86_64.cpp | 6 ++--- .../os_cpu/windows_x86/os_windows_x86.cpp | 4 ++-- src/hotspot/share/asm/assembler.cpp | 4 ++-- src/hotspot/share/asm/assembler.hpp | 6 ++--- src/hotspot/share/c1/c1_Runtime1.cpp | 4 ++-- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 2 +- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 2 +- src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 2 +- src/hotspot/share/interpreter/interpreter.cpp | 4 ++-- .../share/interpreter/templateTable.cpp | 4 ++-- .../share/runtime/stubCodeGenerator.cpp | 4 ++-- .../gtest/aarch64/test_assembler_aarch64.cpp | 2 +- .../gtest/riscv/test_assembler_riscv.cpp | 8 +++---- 57 files changed, 148 insertions(+), 195 deletions(-) diff --git a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp index db0d5e007a02..47c55976a4f3 100644 --- a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp @@ -388,5 +388,5 @@ void DowncallLinker::StubGenerator::generate() { ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. } diff --git a/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp b/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp index c9daef8c6cfa..a92f8f5014cb 100644 --- a/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -181,7 +181,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin __ lea(r0, ExternalAddress(Interpreter::result_handler(method()->result_type()))); __ ret(lr); - __ flush(); + __ invalidate_icache(); } diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp index cffdcf494296..8fd1ffca14cb 100644 --- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -206,7 +206,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ leave(); __ ret(lr); } - __ flush (); + __ invalidate_icache(); return fast_entry; } diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index 638e57b03fee..9620aba88f8c 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -249,8 +249,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Jump to interpreter __ ret(lr); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. UncommonTrapBlob *ut_blob = UncommonTrapBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); @@ -391,8 +390,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ br(r8); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Set exception blob ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); @@ -400,5 +398,3 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { return ex_blob; } #endif // COMPILER2 - - diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 60065ab19406..9cee41626a51 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1612,7 +1612,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(vep_offset != -1, "Must be set"); #endif - __ flush(); + // Code will be copied. No ICache sync required. nmethod* nm = nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -1646,7 +1646,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); + // Code will be copied. No ICache sync required. int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually return nmethod::new_native_nmethod(method, compile_id, @@ -2316,7 +2316,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } } - __ flush(); + // Code will be copied. No ICache sync required. nmethod *nm = nmethod::new_native_nmethod(method, compile_id, @@ -2657,8 +2657,7 @@ void SharedRuntime::generate_deopt_blob() { // Jump to interpreter __ ret(lr); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); @@ -2806,8 +2805,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ stop("Attempting to adjust pc to skip safepoint poll but the return point is not what we expected"); #endif - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Fill-out other meta info SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); @@ -2902,9 +2900,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ ldr(r0, Address(rthread, Thread::pending_exception_offset())); __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // return the blob // frame_size_words or bytes?? @@ -3058,7 +3054,7 @@ BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(con __ ret(lr); - __ flush(); + // Code will be copied. No ICache sync required. return BufferedInlineTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); } @@ -3309,9 +3305,7 @@ RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { __ leave(); __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, frame_size_in_words, oop_maps, false); AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp index 7a0e5aaf3b4e..7f678317a9da 100644 --- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2022, Arm Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -310,7 +310,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - _masm->flush(); + // Code will be copied. No ICache sync required. #ifndef PRODUCT stringStream ss; diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index a070b4f66024..c81bf733a1fb 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -132,7 +132,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) __ ldr(rscratch1, Address(rmethod, entry_offset)); __ br(rscratch1); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); return s; @@ -233,7 +233,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) assert(SharedRuntime::get_handle_wrong_method_stub() != nullptr, "check initialization order"); __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); return s; diff --git a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp index 3a5dd10e82eb..301f54a0070a 100644 --- a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp +++ b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,7 +210,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ bind_literal(safepoint_counter_addr); - __ flush(); + __ invalidate_icache(); guarantee((__ pc() - fast_entry) <= BUFFER_SIZE, "BUFFER_SIZE too small"); diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 3119c7141b1f..59c13e05ef6f 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -449,7 +449,7 @@ class MacroAssembler: public Assembler { int should_not_call_this() { raw_push(FP, LR); should_not_reach_here(); - flush(); + invalidate_icache(); return 2; // frame_size_in_words (FP+LR) } diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index 29fd0aa0a103..5a1845ac0593 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { __ mov(SP, FP); __ pop(RegisterSet(FP) | RegisterSet(PC)); - masm->flush(); + masm->invalidate_icache(); return UncommonTrapBlob::create(&buffer, nullptr, 2 /* LR+FP */); } @@ -280,7 +280,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // ------------- // make sure all code is generated - masm->flush(); + masm->invalidate_icache(); return ExceptionBlob::create(&buffer, oop_maps, framesize_in_words); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 593ba159aa7b..fb24be65294b 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -850,7 +850,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); + __ invalidate_icache(); int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually return nmethod::new_native_nmethod(method, compile_id, @@ -1385,7 +1385,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ b(unlock_done); } - __ flush(); + __ invalidate_icache(); return nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -1654,7 +1654,7 @@ void SharedRuntime::generate_deopt_blob() { __ pop(RegisterSet(FP) | RegisterSet(PC)); - __ flush(); + __ invalidate_icache(); _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); @@ -1734,7 +1734,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); - __ flush(); + __ invalidate_icache(); return SafepointBlob::create(&buffer, oop_maps, frame_size_words); } @@ -1794,7 +1794,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ mov(Rexception_pc, LR); __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); - __ flush(); + __ invalidate_icache(); return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); } diff --git a/src/hotspot/cpu/arm/vtableStubs_arm.cpp b/src/hotspot/cpu/arm/vtableStubs_arm.cpp index 80b3cb3a400f..3f34fa76969e 100644 --- a/src/hotspot/cpu/arm/vtableStubs_arm.cpp +++ b/src/hotspot/cpu/arm/vtableStubs_arm.cpp @@ -110,7 +110,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) address ame_addr = __ pc(); __ ldr(PC, Address(Rmethod, Method::from_compiled_offset())); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); return s; @@ -205,7 +205,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) assert(SharedRuntime::get_handle_wrong_method_stub() != nullptr, "check initialization order"); __ jump(SharedRuntime::get_handle_wrong_method_stub(), relocInfo::runtime_call_type, Rtemp); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); return s; diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index e6a78485411e..87c12f3e4ed5 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -1369,10 +1369,6 @@ class Assembler : public AbstractAssembler { return (0 == addr % a); } - void flush() { - AbstractAssembler::flush(); - } - inline void emit_int32(int); // shadows AbstractAssembler::emit_int32 inline void emit_data(int); inline void emit_data(int, RelocationHolder const&); diff --git a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp index d550c33b1122..e9ca213c72c9 100644 --- a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025 SAP SE. All rights reserved. + * Copyright (c) 2020, 2026 SAP SE. All rights reserved. * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -374,5 +374,5 @@ void DowncallLinker::StubGenerator::generate() { ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. } diff --git a/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp b/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp index dd2503bd54b8..233713b0ecd8 100644 --- a/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp +++ b/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,7 +127,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin __ load_const(R3_RET, AbstractInterpreter::result_handler(method()->result_type())); __ blr(); - __ flush(); + __ invalidate_icache(); } #undef __ diff --git a/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp b/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp index ac3d2d5dba85..033a25b62f2d 100644 --- a/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp +++ b/src/hotspot/cpu/ppc/jniFastGetField_ppc.cpp @@ -154,7 +154,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ load_const_optimized(R12, slow_case_addr, R0); __ call_c_and_return_to_caller(R12); // tail call - __ flush(); + __ invalidate_icache(); return fast_entry; } diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index ab658e9de58b..a1ba80cad5b7 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,8 +141,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ mtlr(R4_ARG2); __ bctr(); - // Make sure all code is generated. - masm->flush(); + // Code will be copied. No ICache sync required. // Set exception blob. return ExceptionBlob::create(&buffer, oop_maps, diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 553934953873..c9b8e8252675 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2169,7 +2169,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, assert(vep_offset != -1, "Must be set"); #endif - __ flush(); + // Code will be copied. No ICache sync required. nmethod* nm = nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -2198,7 +2198,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); + // Code will be copied. No ICache sync required. int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually return nmethod::new_native_nmethod(method, compile_id, @@ -2836,7 +2836,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Done. // -------------------------------------------------------------------------- - __ flush(); + // Code will be copied. No ICache sync required. nmethod *nm = nmethod::new_native_nmethod(method, compile_id, @@ -3203,8 +3203,7 @@ void SharedRuntime::generate_deopt_blob() { __ unimplemented("deopt blob needed only with compiler"); #endif - // Make sure all code is generated - __ flush(); + // Code will be copied. No ICache sync required. _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, first_frame_size_in_bytes / wordSize); @@ -3341,7 +3340,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Return to the interpreter entry point. __ blr(); - masm->flush(); + // Code will be copied. No ICache sync required. return UncommonTrapBlob::create(&buffer, oop_maps, frame_size_in_bytes/wordSize); } @@ -3447,8 +3446,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ blr(); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Fill-out other meta info // CodeBlob frame size is in words. @@ -3534,9 +3532,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ std(R11_scratch1, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); __ b64_patchable(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - // ------------- - // Make sure all code is generated. - masm->flush(); + // Code will be copied. No ICache sync required. // return the blob // frame_size_words or bytes?? diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 35042e841e66..9e8cb838955c 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1162,7 +1162,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M __ resize_frame_absolute(R21_sender_SP, R11_scratch1, R0); __ blr(); - __ flush(); + __ invalidate_icache(); return entry; } @@ -1179,7 +1179,7 @@ address TemplateInterpreterGenerator::generate_Float_floatToFloat16_entry() { __ resize_frame_absolute(R21_sender_SP, R11_scratch1, R0); __ blr(); - __ flush(); + __ invalidate_icache(); return entry; } @@ -1200,7 +1200,7 @@ address TemplateInterpreterGenerator::generate_Float_float16ToFloat_entry() { __ resize_frame_absolute(R21_sender_SP, R11_scratch1, R0); __ blr(); - __ flush(); + __ invalidate_icache(); return entry; } diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index ae5410b12dfc..7d0cfeaea094 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, 2025 SAP SE. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,7 +243,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - _masm->flush(); + // Code will be copied. No ICache sync required. #ifndef PRODUCT stringStream ss; diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 8781230d8126..b3b433cea948 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -514,7 +514,7 @@ void VM_Version::determine_features() { a->blr(); uint32_t *code_end = (uint32_t *)a->pc(); - a->flush(); + a->invalidate_icache(); _features = VM_Version::unknown_m; // Print the detection code. @@ -570,7 +570,7 @@ void VM_Version::config_dscr() { a->blr(); uint32_t *code_end = (uint32_t *)a->pc(); - a->flush(); + a->invalidate_icache(); // Print the detection code. if (PrintAssembly) { diff --git a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp index 73a1cbe090f8..b34f60cdec95 100644 --- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) __ mtctr(R12_scratch2); __ bctr(); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); return s; @@ -224,7 +224,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) __ mtctr(R11_scratch1); __ bctr(); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); return s; diff --git a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp index b11abb912ee5..beb8f457e9d5 100644 --- a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp @@ -383,5 +383,5 @@ void DowncallLinker::StubGenerator::generate() { ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. } diff --git a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp index c8e488d9d691..fc9f224a7675 100644 --- a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp +++ b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -168,7 +168,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin __ movptr(x10, ExternalAddress(Interpreter::result_handler(method()->result_type()))); __ ret(); - __ flush(); + __ invalidate_icache(); } diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index 9755cb9ef16c..dcdbe4a6dc18 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -166,7 +166,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ leave(); __ ret(); } - __ flush(); + __ invalidate_icache(); return fast_entry; } diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp index 5a1fdbe773a1..62c61bf436a8 100644 --- a/src/hotspot/cpu/riscv/runtime_riscv.cpp +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -246,8 +246,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Jump to interpreter __ ret(); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. UncommonTrapBlob* ut_blob = UncommonTrapBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); @@ -389,8 +388,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ jr(t1); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Set exception blob ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index f28230f23bc5..14649fab5b8c 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1392,7 +1392,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(vep_offset != -1, "Must be set"); #endif - __ flush(); + // Code will be copied. No ICache sync required. nmethod* nm = nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -1430,7 +1430,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); + // Code will be copied. No ICache sync required. int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually return nmethod::new_native_nmethod(method, compile_id, @@ -2082,7 +2082,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } } - __ flush(); + // Code will be copied. No ICache sync required. nmethod *nm = nmethod::new_native_nmethod(method, compile_id, @@ -2421,8 +2421,7 @@ void SharedRuntime::generate_deopt_blob() { // Jump to interpreter __ ret(); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); assert(_deopt_blob != nullptr, "create deoptimization blob fail!"); @@ -2567,8 +2566,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ stop("Attempting to adjust pc to skip safepoint poll but the return point is not what we expected"); #endif - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Fill-out other meta info SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); @@ -2663,9 +2661,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ ld(x10, Address(xthread, Thread::pending_exception_offset())); __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // return the blob RuntimeStub* rs_blob = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 0fccce171bbc..70dafd94fe23 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -330,7 +330,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. #ifndef PRODUCT stringStream ss; diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp index 4fc70e7656f2..73948ef6429d 100644 --- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -137,7 +137,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) __ ld(t1, Address(xmethod, entry_offset)); __ jr(t1); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); return s; @@ -246,7 +246,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) assert(SharedRuntime::get_handle_wrong_method_stub() != nullptr, "check initialization order"); __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); return s; diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index 4fe4c31567a0..a10d4c1833d1 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -316,5 +316,5 @@ void DowncallLinker::StubGenerator::generate() { ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. } diff --git a/src/hotspot/cpu/s390/interpreterRT_s390.cpp b/src/hotspot/cpu/s390/interpreterRT_s390.cpp index c9d7adbc36a8..75d8a648a262 100644 --- a/src/hotspot/cpu/s390/interpreterRT_s390.cpp +++ b/src/hotspot/cpu/s390/interpreterRT_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,7 +139,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin iterate(fingerprint); __ load_const_optimized(Z_RET, AbstractInterpreter::result_handler(method()->result_type())); __ z_br(Z_R14); - __ flush(); + __ invalidate_icache(); } #undef __ diff --git a/src/hotspot/cpu/s390/jniFastGetField_s390.cpp b/src/hotspot/cpu/s390/jniFastGetField_s390.cpp index 00c9316c3551..3456afdc674d 100644 --- a/src/hotspot/cpu/s390/jniFastGetField_s390.cpp +++ b/src/hotspot/cpu/s390/jniFastGetField_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ load_const_optimized(Robj, slow_case_addr); __ z_br(Robj); // tail call - __ flush(); + __ invalidate_icache(); return fast_entry; } diff --git a/src/hotspot/cpu/s390/runtime_s390.cpp b/src/hotspot/cpu/s390/runtime_s390.cpp index 658fba069b4c..ddfe8afe2a2d 100644 --- a/src/hotspot/cpu/s390/runtime_s390.cpp +++ b/src/hotspot/cpu/s390/runtime_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,8 +142,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ z_br(handle_exception); - // Make sure all code is generated. - masm->flush(); + // Code will be copied. No ICache sync required. // Set exception blob. OopMapSet *oop_maps = nullptr; diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index b6b22102d011..af2e3c3490f5 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2024 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * Copyright (c) 2026 IBM Corporation. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2220,7 +2220,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, assert(vep_offset != -1, "Must be set"); #endif - __ flush(); + // Code will be copied. No ICache sync required. nmethod* nm = nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -2250,7 +2250,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, int frame_complete = ((intptr_t)__ pc()) - start; // Not complete, period. - __ flush(); + // Code will be copied. No ICache sync required. int stack_slots = SharedRuntime::out_preserve_stack_slots(); // No out slots at all, actually. @@ -2968,7 +2968,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ restore_return_pc(); __ z_br(Z_R1_scratch); - __ flush(); + // Code will be copied. No ICache sync required. ////////////////////////////////////////////////////////////////////// // end of code generation ////////////////////////////////////////////////////////////////////// @@ -3543,8 +3543,7 @@ void SharedRuntime::generate_deopt_blob() { // return to the interpreter entry point. __ z_br(Z_R14); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers, SuperwordUseVX)/wordSize); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); @@ -3682,7 +3681,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // return to the interpreter entry point __ z_br(Z_R14); - masm->flush(); + // Code will be copied. No ICache sync required. return UncommonTrapBlob::create(&buffer, nullptr, framesize_in_bytes/wordSize); } #endif // COMPILER2 @@ -3780,8 +3779,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ z_br(Z_R14); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Fill-out other meta info return SafepointBlob::create(&buffer, oop_maps, RegisterSaver::live_reg_frame_size(RegisterSaver::all_registers, save_vectors)/wordSize); @@ -3863,8 +3861,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ z_br(Z_R1_scratch); // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // return the blob // frame_size_words or bytes?? diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index de57e5e0cc49..e940f0df2b93 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -271,7 +271,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - _masm->flush(); + // Code will be copied. No ICache sync required. #ifndef PRODUCT stringStream ss; diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 95ca00d4d1a6..eb0a5a63223e 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2024 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1142,7 +1142,7 @@ void VM_Version::determine_features() { a->z_br(Z_R14); address code_end = a->pc(); - a->flush(); + a->invalidate_icache(); cbuf.insts()->set_end(code_end); diff --git a/src/hotspot/cpu/s390/vtableStubs_s390.cpp b/src/hotspot/cpu/s390/vtableStubs_s390.cpp index de4049ccacfe..596f3bc1c229 100644 --- a/src/hotspot/cpu/s390/vtableStubs_s390.cpp +++ b/src/hotspot/cpu/s390/vtableStubs_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,7 +141,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) __ z_lg(Z_R1_scratch, in_bytes(Method::from_compiled_offset()), Z_method); __ z_br(Z_R1_scratch); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); return s; @@ -235,7 +235,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); __ z_br(Z_R1_scratch); - masm->flush(); + masm->invalidate_icache(); bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); return s; diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp index 2480e68e7b86..98b52e1d6288 100644 --- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp @@ -381,5 +381,5 @@ void DowncallLinker::StubGenerator::generate() { } ////////////////////////////////////////////////////////////////////////////// - __ flush(); + // Code will be copied. No ICache sync required. } diff --git a/src/hotspot/cpu/x86/icache_x86.hpp b/src/hotspot/cpu/x86/icache_x86.hpp index 92e4fbf15690..a8bdf7f0ec6a 100644 --- a/src/hotspot/cpu/x86/icache_x86.hpp +++ b/src/hotspot/cpu/x86/icache_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,16 +28,6 @@ // Interface for updating the instruction cache. Whenever the VM modifies // code, part of the processor instruction cache potentially has to be flushed. -// On the x86, this is a no-op -- the I-cache is guaranteed to be consistent -// after the next jump, and the VM never modifies instructions directly ahead -// of the instruction fetch path. - -// [phh] It's not clear that the above comment is correct, because on an MP -// system where the dcaches are not snooped, only the thread doing the invalidate -// will see the update. Even in the snooped case, a memory fence would be -// necessary if stores weren't ordered. Fortunately, they are on all known -// x86 implementations. - class ICache : public AbstractICache { public: enum { diff --git a/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp b/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp index 8909df5b3f08..31b074c552be 100644 --- a/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp +++ b/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -295,7 +295,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin __ lea(rax, ExternalAddress(Interpreter::result_handler(method()->result_type()))); __ ret(0); - __ flush(); + __ invalidate_icache(); } diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index 2c4d34c7cd54..caa167357f16 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // tail call __ jump (RuntimeAddress(slow_case_addr), rscratch1); - __ flush (); + __ invalidate_icache(); return fast_entry; } @@ -208,7 +208,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { // tail call __ jump (RuntimeAddress(slow_case_addr), rscratch1); - __ flush (); + __ invalidate_icache(); return fast_entry; } diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp index 5bf65299a0c5..cfd4e8e9df0c 100644 --- a/src/hotspot/cpu/x86/runtime_x86_64.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,8 +231,7 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Jump to interpreter __ ret(0); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. UncommonTrapBlob *ut_blob = UncommonTrapBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); @@ -370,8 +369,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ jmp(r8); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Set exception blob ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 8d257565c939..36cb8d41e820 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2021,7 +2021,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(vep_offset != -1, "Must be set"); #endif - __ flush(); + // Code will be copied. No ICache sync required. nmethod* nm = nmethod::new_native_nmethod(method, compile_id, masm->code(), @@ -2050,7 +2050,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); + // Code will be copied. No ICache sync required. int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually return nmethod::new_native_nmethod(method, compile_id, @@ -2712,7 +2712,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, - __ flush(); + // Code will be copied. No ICache sync required. nmethod *nm = nmethod::new_native_nmethod(method, compile_id, @@ -3064,8 +3064,7 @@ void SharedRuntime::generate_deopt_blob() { // Jump to interpreter __ ret(0); - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); @@ -3248,8 +3247,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) __ stop("Attempting to adjust pc to skip safepoint poll but the return point is not what we expected"); #endif - // Make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // Fill-out other meta info SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); @@ -3340,9 +3338,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset())); __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. // return the blob // frame_size_words or bytes?? @@ -3864,7 +3860,7 @@ BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(con __ bind(skip); __ ret(0); - __ flush(); + // Code will be copied. No ICache sync required. return BufferedInlineTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); } @@ -4021,9 +4017,7 @@ RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset())); __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - // ------------- - // make sure all code is generated - masm->flush(); + // Code will be copied. No ICache sync required. RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, false); AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index edc83fa7c562..095767663e55 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -363,7 +363,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - _masm->flush(); + // Code will be copied. No ICache sync required. #ifndef PRODUCT stringStream ss; diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp index 81929e78d585..f47d1ad2ad5b 100644 --- a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp +++ b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,7 +131,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) address ame_addr = __ pc(); __ jmp( Address(rbx, entry_offset)); - masm->flush(); + masm->invalidate_icache(); slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, index_dependent_slop); @@ -248,7 +248,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) // dirty work. __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); - masm->flush(); + masm->invalidate_icache(); slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, index_dependent_slop); diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index e3291d3a6ca9..31ce1b41f39d 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,7 +134,7 @@ bool os::win32::register_code_area(char *low, char *high) { pDCD = (pDynamicCodeData) masm->pc(); masm->jump(RuntimeAddress((address)&HandleExceptionFromCodeCache), rscratch1); - masm->flush(); + masm->invalidate_icache(); // Create an Unwind Structure specifying no unwind info // other than an Exception Handler diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index 9e342d23afd8..5de8a6dfb10b 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ void AbstractAssembler::end_a_const(CodeSection* cs) { set_code_section(cs); } -void AbstractAssembler::flush() { +void AbstractAssembler::invalidate_icache() { ICache::invalidate_range(addr_at(0), offset()); } diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index bfe785fb94e9..b24e65e12621 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -311,8 +311,8 @@ class AbstractAssembler : public ResourceObj { // Creation AbstractAssembler(CodeBuffer* code); - // ensure buf contains all code (call this before using/copying the code) - void flush(); + // Invalidate ICache after writing code to its final location. + void invalidate_icache(); void emit_int8( int x1) { code_section()->emit_int8(narrow_cast(x1)); } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 118758f3ea49..d4b1f3a111e7 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -236,8 +236,8 @@ CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, StubId id, const char // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned) sasm->align(BytesPerWord); - // make sure all code is in code buffer - sasm->flush(); + + // Code will be copied. No ICache sync required. frame_size = sasm->frame_size(); must_gc_arguments = sasm->must_gc_arguments(); diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 774ea372bad8..cf4bacbb98b2 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -575,7 +575,7 @@ void G1BarrierSetC2::emit_stubs(CodeBuffer& cb) const { } stubs->at(i)->emit_code(masm); } - masm.flush(); + // Code will be copied. No ICache sync required. } #ifndef PRODUCT diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 1bac056a2253..b9b2c6a0f7af 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -888,7 +888,7 @@ void ShenandoahBarrierSetC2::emit_stubs(CodeBuffer& cb) const { skipped_after, skipped_before, skipped_after - skipped_before); #endif - masm.flush(); + // Code will be copied. No ICache sync required. } void ShenandoahBarrierStubC2::register_stub(ShenandoahBarrierStubC2* stub) { diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index 6c82f388aae6..7d732347c296 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -320,7 +320,7 @@ void ZBarrierSetC2::emit_stubs(CodeBuffer& cb) const { stubs->at(i)->emit_code(masm); } - masm.flush(); + // Code will be copied. No ICache sync required. } int ZBarrierSetC2::estimate_stub_size() const { diff --git a/src/hotspot/share/interpreter/interpreter.cpp b/src/hotspot/share/interpreter/interpreter.cpp index 1f327152e0c6..a3850a5eab41 100644 --- a/src/hotspot/share/interpreter/interpreter.cpp +++ b/src/hotspot/share/interpreter/interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,7 +105,7 @@ CodeletMark::~CodeletMark() { // Align so printing shows nop's instead of random code at the end (Codelets are aligned). (*_masm)->align(wordSize); // Make sure all code is in code buffer. - (*_masm)->flush(); + (*_masm)->invalidate_icache(); // Commit Codelet. int committed_code_size = (*_masm)->code()->pure_insts_size(); diff --git a/src/hotspot/share/interpreter/templateTable.cpp b/src/hotspot/share/interpreter/templateTable.cpp index 48845511f18e..688c87a10b71 100644 --- a/src/hotspot/share/interpreter/templateTable.cpp +++ b/src/hotspot/share/interpreter/templateTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ void Template::generate(InterpreterMacroAssembler* masm) { TemplateTable::_masm = masm; // code generation _gen(_arg); - masm->flush(); + masm->invalidate_icache(); } diff --git a/src/hotspot/share/runtime/stubCodeGenerator.cpp b/src/hotspot/share/runtime/stubCodeGenerator.cpp index 252f90e1bde3..7f5c2286faea 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.cpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -291,7 +291,7 @@ StubCodeMark::StubCodeMark(StubCodeGenerator* cgen, StubId stub_id) : StubCodeMa } StubCodeMark::~StubCodeMark() { - _cgen->assembler()->flush(); + _cgen->assembler()->invalidate_icache(); _cdesc->set_end(_cgen->assembler()->pc()); assert(StubCodeDesc::_list == _cdesc, "expected order on list"); #ifndef PRODUCT diff --git a/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp b/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp index db240aeee904..08d73d19655e 100644 --- a/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp +++ b/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp @@ -568,7 +568,7 @@ struct GtestFriendToMacroAssembler { real_mode); masm.ret(lr); - masm.flush(); // icache invalidate + masm.invalidate_icache(); } { diff --git a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp index 55504c34b0fa..6281144fed63 100644 --- a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp +++ b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -48,7 +48,7 @@ class CmovTester { _masm.mv(c_rarg0, c_rarg2); _masm.ret(); } - _masm.flush(); // icache invalidate + _masm.invalidate_icache(); int64_t ret = ((zicond_func)entry)(a0, a1, a2, a3); ASSERT_EQ(ret, result); BufferBlob::free(bb); @@ -175,7 +175,7 @@ class CmpxchgTester { _masm.ret(); _func = ((cmpxchg_func)entry); } - _masm.flush(); // icache invalidate + _masm.invalidate_icache(); } ~CmpxchgTester() { @@ -594,7 +594,7 @@ class WeakCmpxchgTester { _masm.ret(); _weak = ((weak_cmpxchg_func)entry); } - _masm.flush(); // icache invalidate + _masm.invalidate_icache(); } TESTSIZE weak_cmpxchg(intptr_t addr, TESTSIZE expected, TESTSIZE new_value) { From caf2c84d4717fa91bb078bdabd8ce10f110ac0e3 Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Fri, 28 Aug 2026 11:31:05 +0000 Subject: [PATCH 133/223] 8374574: Enable AES CBC intrinsic for PowerPC Reviewed-by: mdoerr, dbriemann --- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 302 ++++++++++++++++++++++ 1 file changed, 302 insertions(+) diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 9f30dde1103f..1470ea931b67 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -3013,6 +3013,306 @@ class StubGenerator: public StubCodeGenerator { return start; } + // ========================================================================== + // AES helper functions for PPC64 + // + // These emit the AES round instructions. + // Each call to these helpers emits a sequence of vcipher/vncipher + // instructions. + // + // ========================================================================== + // Emits the AES encrypt round instructions. + // + // vRet: in/out — the AES state (plaintext in, ciphertext out) + // key: register holding pointer to expanded key array + // keylen: register holding key length (44/52/60) + // + void aes_encrypt_rounds(VectorRegister vRet, + Register key, Register keylen, Register tmp, + VectorRegister vKey1, VectorRegister vKey2, + VectorRegister vKey3, VectorRegister vKey4) { + Label L_doLast; + + // round 0: AddRoundKey + __ load_word_vector_unaligned(vKey1, 0, key, tmp); + __ vxor (vRet, vRet, vKey1); + + // rounds 2-5 + __ load_word_vector_unaligned(vKey1, 16, key, tmp); + __ load_word_vector_unaligned(vKey2, 32, key, tmp); + __ load_word_vector_unaligned(vKey3, 48, key, tmp); + __ load_word_vector_unaligned(vKey4, 64, key, tmp); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // rounds 6-9 + __ load_word_vector_unaligned(vKey1, 80, key, tmp); + __ load_word_vector_unaligned(vKey2, 96, key, tmp); + __ load_word_vector_unaligned(vKey3, 112, key, tmp); + __ load_word_vector_unaligned(vKey4, 128, key, tmp); + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + __ vcipher (vRet, vRet, vKey3); + __ vcipher (vRet, vRet, vKey4); + + // rounds 10-11 + __ load_word_vector_unaligned(vKey1, 144, key, tmp); + __ load_word_vector_unaligned(vKey2, 160, key, tmp); + + __ cmpwi (CR0, keylen, 44); // AES-128 -> final rounds + __ beq (CR0, L_doLast); + + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // rounds 12-13 + __ load_word_vector_unaligned(vKey1, 176, key, tmp); + __ load_word_vector_unaligned(vKey2, 192, key, tmp); + + __ cmpwi (CR0, keylen, 52); // AES-192 -> final rounds + __ beq (CR0, L_doLast); +#ifdef ASSERT + __ cmpwi (CR0, keylen, 60); + __ asm_assert_eq(FILE_AND_LINE ": aes_encrypt_rounds - invalid key length"); +#endif + + __ vcipher (vRet, vRet, vKey1); + __ vcipher (vRet, vRet, vKey2); + + // rounds 14-15 + __ load_word_vector_unaligned(vKey1, 208, key, tmp); + __ load_word_vector_unaligned(vKey2, 224, key, tmp); + + __ bind(L_doLast); + __ vcipher (vRet, vRet, vKey1); + __ vcipherlast (vRet, vRet, vKey2); + } + + + // ========================================================================== + // Emits the AES decrypt round instructions. + // + // vRet: in/out — the AES state (ciphertext in, plaintext out) + // key: register holding pointer to expanded key array + // keylen: register holding key length (44/52/60) + // + void aes_decrypt_rounds(VectorRegister vRet, + Register key, Register keylen, Register tmp, + VectorRegister vKey1, VectorRegister vKey2, + VectorRegister vKey3, VectorRegister vKey4, + VectorRegister vKey5) { + Label L_doLast, L_do44, L_do52; + + __ cmpwi (CR0, keylen, 44); + __ beq (CR0, L_do44); + + __ cmpwi (CR0, keylen, 52); + __ beq (CR0, L_do52); + +#ifdef ASSERT + __ cmpwi (CR0, keylen, 60); + __ asm_assert_eq(FILE_AND_LINE ": aes_decrypt_rounds - invalid key length"); +#endif + // ---- AES-256: round keys 15-11 ---- + __ load_word_vector_unaligned(vKey1, 224, key, tmp); + __ load_word_vector_unaligned(vKey2, 208, key, tmp); + __ load_word_vector_unaligned(vKey3, 192, key, tmp); + __ load_word_vector_unaligned(vKey4, 176, key, tmp); + __ load_word_vector_unaligned(vKey5, 160, key, tmp); + + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + __ b (L_doLast); + + __ align(32); + // ---- AES-192: round keys 13-11 ---- + __ bind (L_do52); + __ load_word_vector_unaligned(vKey1, 192, key, tmp); + __ load_word_vector_unaligned(vKey2, 176, key, tmp); + __ load_word_vector_unaligned(vKey3, 160, key, tmp); + + __ vxor (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ b (L_doLast); + + __ align(32); + // ---- AES-128: round key 11 ---- + __ bind (L_do44); + __ load_word_vector_unaligned(vKey1, 160, key, tmp); + __ vxor (vRet, vRet, vKey1); + + // ---- Common rounds 10-1 ---- + __ bind (L_doLast); + __ load_word_vector_unaligned(vKey1, 144, key, tmp); + __ load_word_vector_unaligned(vKey2, 128, key, tmp); + __ load_word_vector_unaligned(vKey3, 112, key, tmp); + __ load_word_vector_unaligned(vKey4, 96, key, tmp); + __ load_word_vector_unaligned(vKey5, 80, key, tmp); + + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipher (vRet, vRet, vKey5); + __ load_word_vector_unaligned(vKey1, 64, key, tmp); + __ load_word_vector_unaligned(vKey2, 48, key, tmp); + __ load_word_vector_unaligned(vKey3, 32, key, tmp); + __ load_word_vector_unaligned(vKey4, 16, key, tmp); + __ load_word_vector_unaligned(vKey5, 0, key, tmp); + __ vncipher (vRet, vRet, vKey1); + __ vncipher (vRet, vRet, vKey2); + __ vncipher (vRet, vRet, vKey3); + __ vncipher (vRet, vRet, vKey4); + __ vncipherlast (vRet, vRet, vKey5); + } + + // ========================================================================== + // CBC Encrypt stub — using helper functions + // from: R3_ARG1 - source byte array address (plaintext) + // to: R4_ARG2 - destination byte array address (ciphertext) + // key: R5_ARG3 - round key array + // rvec: R6_ARG4 - r vector byte array address (initialization vector) + // input_len: R7_ARG5 - length of input in bytes + // + // Returns: + // R3_RET - number of bytes processed + // + address generate_cipherBlockChaining_encryptAESCrypt() { + assert(UseAESIntrinsics, "need AES instructions support"); + StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + address start = __ function_entry(); + + Label L_enc_loop; + + Register from = R3_ARG1; + Register to = R4_ARG2; + Register key = R5_ARG3; + Register rvec = R6_ARG4; + Register input_len = R7_ARG5; + + Register keylen = R8; + Register tmp = R9; + Register len = R10; + + VectorRegister vRet = VR0; + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + VectorRegister vIn = VR5; + VectorRegister vp = VR6; // permute vector for P8 LE byte accesses + VectorRegister vTmp = VR7; + + __ mr (len, input_len); + + // vp must be computed once, before any byte vector access. Clobbers R0. + __ compute_vp_for_byte_vector_unaligned(vp, /*temp*/ vRet); + + __ load_byte_vector_unaligned(vRet, 0, rvec, tmp, vp); + + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - + arrayOopDesc::base_offset_in_bytes(T_INT), key); + + __ align(32); + __ bind(L_enc_loop); + __ load_byte_vector_unaligned(vIn, 0, from, tmp, vp); + __ addi (from, from, 16); + __ vxor (vRet, vRet, vIn); // CBC XOR + aes_encrypt_rounds(vRet, key, keylen, tmp, vKey1, vKey2, vKey3, vKey4); + __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp, vTmp); + __ addi (to, to, 16); + __ addic_ (len, len, -16); + __ bne (CR0, L_enc_loop); + + // save the last ciphertext block in rvec; it is the IV for the next call + __ store_byte_vector_unaligned(vRet, 0, rvec, tmp, vp, vTmp); + __ mr (R3_RET, input_len); + __ blr(); + + return start; + } + + // ========================================================================== + // CBC Decrypt stub + // Arguments: + // R3_ARG1 - from: source byte array address (ciphertext) + // R4_ARG2 - to: destination byte array address (plaintext) + // R5_ARG3 - key: round key array + // R6_ARG4 - rvec: r vector byte array address (in/out), holds the + // initialization vector on entry and is updated with + // the last ciphertext block on exit + // R7_ARG5 - input_len: length of input in bytes, a multiple of 16 + // + // Returns: + // R3_RET - number of bytes processed + // ========================================================================== + + address generate_cipherBlockChaining_decryptAESCrypt() { + assert(UseAESIntrinsics, "need AES instructions support"); + StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + address start = __ function_entry(); + + Label L_dec_loop; + + Register from = R3_ARG1; + Register to = R4_ARG2; + Register key = R5_ARG3; + Register rvec = R6_ARG4; + Register input_len = R7_ARG5; + + Register keylen = R8; + Register tmp = R9; + Register len = R10; + + VectorRegister vRet = VR0; + VectorRegister vKey1 = VR1; + VectorRegister vKey2 = VR2; + VectorRegister vKey3 = VR3; + VectorRegister vKey4 = VR4; + VectorRegister vKey5 = VR5; + VectorRegister vIV = VR6; + VectorRegister vSavedCT = VR7; + VectorRegister vp = VR8; // permute vector for P8 LE byte accesses + VectorRegister vTmp = VR9; + __ mr (len, input_len); + // vp must be computed before any byte vector access. Clobbers R0. + __ compute_vp_for_byte_vector_unaligned(vp, /*temp*/ vRet); + + __ load_byte_vector_unaligned(vIV, 0, rvec, tmp, vp); + + __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - + arrayOopDesc::base_offset_in_bytes(T_INT), key); + + __ align(32); + __ bind(L_dec_loop); + __ load_byte_vector_unaligned(vRet, 0, from, tmp, vp); + __ addi (from, from, 16); + __ vor (vSavedCT, vRet, vRet); // AES will destroy vRet + aes_decrypt_rounds(vRet, key, keylen, tmp, vKey1, vKey2, vKey3, vKey4, vKey5); + __ vxor (vRet, vRet, vIV); // CBC XOR (after decrypt) + __ vor (vIV, vSavedCT, vSavedCT); // IV = previous ciphertext + __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp, vTmp); + __ addi (to, to, 16); + __ addic_ (len, len, -16); + __ bne (CR0, L_dec_loop); + + __ store_byte_vector_unaligned(vIV, 0, rvec, tmp, vp, vTmp); + __ mr (R3_RET, input_len); + __ blr(); + + return start; + } + address generate_sha256_implCompress(StubId stub_id) { assert(UseSHA, "need SHA instructions"); bool multi_block; @@ -4889,6 +5189,8 @@ void generate_lookup_secondary_supers_table_stub() { if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); } if (UseSHA256Intrinsics) { From cb6013429f077bde76d1c53ad8929f70c36cc2e0 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 28 Aug 2026 12:37:36 +0000 Subject: [PATCH 134/223] 8390948: G1: Simplify the selection logic in G1CollectionSet::select_candidates_from_marking() Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 47 ++++++++------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index a30386b38763..44c3695d296e 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -413,7 +413,7 @@ void G1CollectionSet::add_optional_group(G1CSetCandidateGroup* group, double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) { uint num_expensive_regions = 0; - uint num_inital_regions = 0; + uint num_initial_regions = 0; uint num_initial_groups = 0; uint num_optional_regions = 0; @@ -424,8 +424,8 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); - uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); - uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); + uint min_num_old_cset_regions = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); + uint max_num_old_cset_regions = MAX2(min_num_old_cset_regions, _policy->calc_max_old_cset_length()); bool check_time_remaining = _policy->use_adaptive_num_young_regions(); G1CSetCandidateGroupList* from_marking_groups = &candidates()->from_marking_groups(); @@ -435,13 +435,13 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " "Min %u regions, max %u regions, available %u regions (%u groups), " "time remaining %1.2fms, optional threshold %1.2fms", - min_old_cset_length, max_old_cset_length, from_marking_groups->num_regions(), from_marking_groups->length(), + min_num_old_cset_regions, max_num_old_cset_regions, from_marking_groups->num_regions(), from_marking_groups->length(), time_remaining_ms, optional_threshold_ms); G1CSetCandidateGroupList selected_groups; for (G1CSetCandidateGroup* group : *from_marking_groups) { - if (num_inital_regions + num_optional_regions >= max_old_cset_length) { + if (num_initial_regions + num_optional_regions >= max_num_old_cset_regions) { // Added maximum number of old regions to the CSet. print_finish_message("Maximum number of regions reached", true); break; @@ -459,15 +459,15 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) } time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - // Add regions to old set until we reach the minimum amount - if (num_inital_regions < min_old_cset_length) { + // Add regions to old set until we reach the minimum amount or reach the optional threshold. + if (num_initial_regions < min_num_old_cset_regions || (check_time_remaining && time_remaining_ms > optional_threshold_ms)) { num_initial_groups++; add_group_to_collection_set(group); selected_groups.append(group); - num_inital_regions += group->length(); + num_initial_regions += group->length(); predicted_initial_time_ms += predicted_time_ms; // Record the number of regions added with no time remaining @@ -479,28 +479,15 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) // to the CSet if we reach the minimum. print_finish_message("Region amount reached min", true); break; + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up. + add_optional_group(group, + num_optional_regions, + predicted_optional_time_ms, + predicted_time_ms); } else { - // Keep adding regions to old set until we reach the optional threshold - if (time_remaining_ms > optional_threshold_ms) { - num_initial_groups++; - - add_group_to_collection_set(group); - selected_groups.append(group); - - num_inital_regions += group->length(); - - predicted_initial_time_ms += predicted_time_ms; - - } else if (time_remaining_ms > 0) { - // Keep adding optional regions until time is up. - add_optional_group(group, - num_optional_regions, - predicted_optional_time_ms, - predicted_time_ms); - } else { - print_finish_message("Predicted time too high", true); - break; - } + print_finish_message("Predicted time too high", true); + break; } } @@ -523,7 +510,7 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) selected_groups.num_regions(), selected_groups.length(), _optional_groups.num_regions(), _optional_groups.length(), predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); - assert(selected_groups.num_regions() == num_inital_regions, "must be"); + assert(selected_groups.num_regions() == num_initial_regions, "must be"); assert(_optional_groups.num_regions() == num_optional_regions, "must be"); return time_remaining_ms; } From b7624987111350244e2be5bcd1b888a05a75a9e2 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 28 Aug 2026 12:39:22 +0000 Subject: [PATCH 135/223] 8391295: Net.c and other native code cleanup Reviewed-by: djelinski, michaelm --- src/java.base/unix/native/libnio/ch/Net.c | 19 ++++---- .../unix/native/libnio/ch/UnixDomainSockets.c | 8 ++-- .../native/libnio/ch/UnixFileDispatcherImpl.c | 8 ++-- .../native/libnio/ch/FileDispatcherImpl.c | 18 +++++--- src/java.base/windows/native/libnio/ch/Net.c | 45 ++++++++++--------- .../native/libnio/ch/UnixDomainSockets.c | 7 ++- .../libnio/fs/WindowsNativeDispatcher.c | 6 +-- 7 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c index 0779294cdae3..8fc3d11b5e78 100644 --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -276,8 +276,7 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, */ if (domain == AF_INET6 && ipv4_available()) { int arg = 0; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, - sizeof(int)) < 0) { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, sizeof(int)) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Unable to set IPV6_V6ONLY"); @@ -288,8 +287,7 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, if (reuse) { int arg = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, - sizeof(arg)) < 0) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg)) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Unable to set SO_REUSEADDR"); @@ -418,7 +416,6 @@ Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfd } /* ECONNABORTED => restart accept */ } - if (newfd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return IOS_UNAVAILABLE; @@ -427,14 +424,18 @@ Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfd JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); return IOS_THROWN; } - setfdval(env, newfdo, newfd); remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); - CHECK_NULL_RETURN(remote_ia, IOS_THROWN); - + if (remote_ia == NULL) { + close(newfd); + return IOS_THROWN; + } isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); - CHECK_NULL_RETURN(isa, IOS_THROWN); + if (isa == NULL) { + close(newfd); + return IOS_THROWN; + } (*env)->SetObjectArrayElement(env, isaa, 0, isa); return 1; diff --git a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c index c43c3b906952..299ccc461986 100644 --- a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c +++ b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,8 +172,10 @@ Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo setfdval(env, newfdo, newfd); address = sockaddrToUnixAddressBytes(env, &sa, sa_len); - CHECK_NULL_RETURN(address, IOS_THROWN); - + if (address == NULL) { + close(newfd); + return IOS_THROWN; + } (*env)->SetObjectArrayElement(env, array, 0, address); return 1; diff --git a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c index 0c6328c56905..08321b602e5b 100644 --- a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,9 +191,9 @@ Java_sun_nio_ch_UnixFileDispatcherImpl_available0(JNIEnv *env, jobject this, job if (fstat(fd, &fbuf) != -1) { int mode = fbuf.st_mode; if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { - int n = ioctl(fd, FIONREAD, &n); - if (n >= 0) { - return n; + int available; + if (ioctl(fd, FIONREAD, &available) >= 0) { + return available; } } else if (S_ISREG(mode)) { size = fbuf.st_size; diff --git a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c index ef5c3e079295..635a5ccd818a 100644 --- a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -435,32 +435,36 @@ Java_sun_nio_ch_FileDispatcherImpl_isOther0(JNIEnv *env, jobject this, jobject f HANDLE handle = (HANDLE)(handleval(env, fdo)); BY_HANDLE_FILE_INFORMATION finfo; - if (!GetFileInformationByHandle(handle, &finfo)) + if (!GetFileInformationByHandle(handle, &finfo)) { JNU_ThrowIOExceptionWithLastError(env, "isOther failed"); - DWORD fattr = finfo.dwFileAttributes; + return JNI_FALSE; + } + DWORD fattr = finfo.dwFileAttributes; if ((fattr & FILE_ATTRIBUTE_DEVICE) != 0) return (jboolean)JNI_TRUE; if ((fattr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; void* lpOutBuffer = (void*)malloc(size*sizeof(char)); - if (lpOutBuffer == NULL) + if (lpOutBuffer == NULL) { JNU_ThrowOutOfMemoryError(env, "isOther failed"); + return JNI_FALSE; + } DWORD bytesReturned; if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, lpOutBuffer, (DWORD)size, &bytesReturned, NULL)) { free(lpOutBuffer); JNU_ThrowIOExceptionWithLastError(env, "isOther failed"); + return JNI_FALSE; } ULONG reparseTag = (*((PULONG)lpOutBuffer)); free(lpOutBuffer); - return reparseTag == IO_REPARSE_TAG_SYMLINK ? - (jboolean)JNI_FALSE : (jboolean)JNI_TRUE; + return reparseTag == IO_REPARSE_TAG_SYMLINK ? JNI_FALSE : JNI_TRUE; } - return (jboolean)JNI_FALSE; + return JNI_FALSE; } JNIEXPORT jint JNICALL diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c index adfd67b50171..aff73441cfd7 100644 --- a/src/java.base/windows/native/libnio/ch/Net.c +++ b/src/java.base/windows/native/libnio/ch/Net.c @@ -158,25 +158,19 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, int domain = (preferIPv6) ? AF_INET6 : AF_INET; s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - if (s != INVALID_SOCKET) { - SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); - - /* Attempt to disable IPV6_V6ONLY to ensure dual-socket support; ignore errors */ - if (domain == AF_INET6) { - int opt = 0; - setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - (const char *)&opt, sizeof(opt)); - } - - /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ - if (!stream) { - setConnectionReset(s, FALSE); - } - - } else { + if (s == INVALID_SOCKET) { NET_ThrowNew(env, WSAGetLastError(), "socket"); + return IOS_THROWN; + } + SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); + + /* Attempt to disable IPV6_V6ONLY to ensure dual-socket support; ignore errors */ + if (domain == AF_INET6 && ipv4_available()) { + int opt = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)); } + /* Enable SIO_LOOPBACK_FAST_PATH on TCP sockets if possible */ if (stream && fastLoopback) { static int loopback_available = 1; if (loopback_available) { @@ -186,11 +180,18 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, loopback_available = 0; } else { NET_ThrowNew(env, rv, "fastLoopback"); + closesocket(s); + return IOS_THROWN; } } } } + /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ + if (!stream) { + setConnectionReset(s, FALSE); + } + return (jint)s; } @@ -290,15 +291,19 @@ Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfd JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); return IOS_THROWN; } - SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); setfdval(env, newfdo, newfd); remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); - CHECK_NULL_RETURN(remote_ia, IOS_THROWN); - + if (remote_ia == NULL) { + closesocket(newfd); + return IOS_THROWN; + } isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); - CHECK_NULL_RETURN(isa, IOS_THROWN); + if (isa == NULL) { + closesocket(newfd); + return IOS_THROWN; + } (*env)->SetObjectArrayElement(env, isaa, 0, isa); return 1; diff --git a/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c index e29d8e28efc7..b323ebbcc7b8 100644 --- a/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c +++ b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,10 @@ Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo setfdval(env, newfdo, newfd); address = sockaddrToUnixAddressBytes(env, &sa, sa_len); - CHECK_NULL_RETURN(address, IOS_THROWN); + if (address == NULL) { + closesocket(newfd); + return IOS_THROWN; + } (*env)->SetObjectArrayElement(env, array, 0, address); return 1; diff --git a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 07452cbef0a0..87beaf4fc666 100644 --- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -901,8 +901,8 @@ Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountSid0(JNIEnv* env, { WCHAR domain[255]; WCHAR name[255]; - DWORD domainLen = sizeof(domain); - DWORD nameLen = sizeof(name); + DWORD domainLen = (DWORD)(sizeof(domain) / sizeof(domain[0])); + DWORD nameLen = (DWORD)(sizeof(name) / sizeof(name[0])); SID_NAME_USE use; PSID sid = jlong_to_ptr(address); jstring s; @@ -932,7 +932,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountName0(JNIEnv* env, LPCWSTR accountName = jlong_to_ptr(nameAddress); PSID sid = jlong_to_ptr(sidAddress); WCHAR domain[255]; - DWORD domainLen = sizeof(domain); + DWORD domainLen = (DWORD)(sizeof(domain) / sizeof(domain[0])); SID_NAME_USE use; if (LookupAccountNameW(NULL, accountName, sid, (LPDWORD)&cbSid, From 95782058099f72370fdf959ffe5a8629ac5f0dec Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 28 Aug 2026 12:48:40 +0000 Subject: [PATCH 136/223] 8384133: StringTableCorruptionTest should keep Strings alive to reliably trigger Reviewed-by: coleenp, dholmes --- .../StringTableCorruptionTest.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java index e4d6a2e5d0f9..b131ebc4c8ee 100644 --- a/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java +++ b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java @@ -34,11 +34,16 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; public class StringTableCorruptionTest { + // Retain all Strings to make sure StringTable grows and keeps our corrupted String alive + static final List RETAIN = new ArrayList<>(); + public static void main(String[] args) throws Exception { if (args.length > 0) { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("--add-opens", "java.base/java.lang=ALL-UNNAMED", @@ -51,9 +56,20 @@ public static void main(String[] args) throws Exception { Field f = String.class.getDeclaredField("value"); f.setAccessible(true); - f.set("s1".intern(), f.get("s2")); + + // Put a String into StringTable and corrupt it. + String s1 = "s1".intern(); + f.set(s1, f.get("s2")); + RETAIN.add(s1); + + // Fill in StringTable to trigger growth. + // Also do a few intentional GCs to make sure test behavior does not depend on accidental GCs. for (int i = 0; i < 4_000_000; i++) { - ("s_" + i).intern(); + String s = ("s_" + i).intern(); + RETAIN.add(s); + if (i % 100_000 == 0) { + System.gc(); + } } } } From 37b7397236a323a767320345d5198a79638309cf Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 28 Aug 2026 15:56:52 +0000 Subject: [PATCH 137/223] 8391235: Zero build fails due to GCC-15.2.0 stringop-overflow warning after JDK-8390310 Reviewed-by: kdnilsen, shade --- .../share/gc/shenandoah/shenandoahInPlacePromoter.cpp | 8 ++++++++ .../share/gc/shenandoah/shenandoahInPlacePromoter.hpp | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp index 8b4c5291877b..efea98b61f07 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp @@ -26,12 +26,20 @@ #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahInPlacePromoter.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahScanRemembered.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" +void ShenandoahInPlacePromotionPlanner::RegionPromotionStats::update(ShenandoahHeapRegion* region) { + count++; + usage += region->get_live_data_bytes(); + free += region->free(); + garbage += region->garbage(); +} + ShenandoahInPlacePromotionPlanner::ShenandoahInPlacePromotionPlanner(const ShenandoahGenerationalHeap* heap) : _old_garbage_threshold(ShenandoahHeapRegion::region_size_bytes() * heap->old_generation()->heuristics()->get_old_garbage_threshold() / 100) , _pip_used_threshold(ShenandoahHeapRegion::region_size_bytes() * ShenandoahGenerationalMinPIPUsage / 100) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp index 4777c1893e3f..b489a591be75 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.hpp @@ -26,7 +26,6 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHINPLACEPROMOTER_HPP #include "gc/shenandoah/shenandoahFreeSet.hpp" -#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" class ShenandoahMarkingContext; @@ -82,12 +81,7 @@ class ShenandoahInPlacePromotionPlanner { size_t garbage; RegionPromotionStats() : count(0), usage(0), free(0), garbage(0) {} - void update(ShenandoahHeapRegion* region) { - count++; - usage += region->get_live_data_bytes(); - free += region->free(); - garbage += region->garbage(); - } + void update(ShenandoahHeapRegion* region); }; const size_t _old_garbage_threshold; From e5968d896713148c9d6302bed7ad1cde78654187 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 28 Aug 2026 16:19:34 +0000 Subject: [PATCH 138/223] 8391224: Fix Amazon copyright in various files Reviewed-by: shade, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahCardStats.cpp | 2 +- .../sun/jvm/hotspot/gc/shenandoah/ShenandoahFreeSet.java | 2 +- test/hotspot/gtest/oops/test_objArrayOop.cpp | 2 +- test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java | 2 +- test/hotspot/jtreg/compiler/intrinsics/zip/TestFpRegsABI.java | 2 +- test/hotspot/jtreg/gtest/ArrayTests.java | 2 +- test/hotspot/jtreg/gtest/ObjArrayTests.java | 2 +- .../gc/detailed/TestShenandoahEvacuationInformationEvent.java | 2 +- .../gc/detailed/TestShenandoahPromotionInformationEvent.java | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardStats.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCardStats.cpp index fc59af99817e..ba0b8c956ec9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardStats.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shenandoah/ShenandoahFreeSet.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shenandoah/ShenandoahFreeSet.java index 9ca8e1deb04e..fdd835c14bdd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shenandoah/ShenandoahFreeSet.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shenandoah/ShenandoahFreeSet.java @@ -1,5 +1,5 @@ /* - * * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/gtest/oops/test_objArrayOop.cpp b/test/hotspot/gtest/oops/test_objArrayOop.cpp index 1dd8cf752548..cc5bb2326882 100644 --- a/test/hotspot/gtest/oops/test_objArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_objArrayOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java b/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java index bcc3b9541ba5..b28cbca40142 100644 --- a/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java +++ b/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/compiler/intrinsics/zip/TestFpRegsABI.java b/test/hotspot/jtreg/compiler/intrinsics/zip/TestFpRegsABI.java index 46ecb64096b8..3a3c8b2765d8 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/zip/TestFpRegsABI.java +++ b/test/hotspot/jtreg/compiler/intrinsics/zip/TestFpRegsABI.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/gtest/ArrayTests.java b/test/hotspot/jtreg/gtest/ArrayTests.java index d3a8498d5ebf..2f470a293780 100644 --- a/test/hotspot/jtreg/gtest/ArrayTests.java +++ b/test/hotspot/jtreg/gtest/ArrayTests.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/gtest/ObjArrayTests.java b/test/hotspot/jtreg/gtest/ObjArrayTests.java index 67d994768f9c..238713965e50 100644 --- a/test/hotspot/jtreg/gtest/ObjArrayTests.java +++ b/test/hotspot/jtreg/gtest/ObjArrayTests.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java index 75fe1ee78846..a75d21d83c5f 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java index c315694718b5..6a3c1ba1e567 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright Amazon.com Inc. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From f8c6117ce526bf2275c1cdbd528f1d1277efa397 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 28 Aug 2026 16:37:53 +0000 Subject: [PATCH 139/223] 8391222: Clarify the explanation of line terminator sequences in java.util.Properties.load(Reader) Reviewed-by: iris, jpai, mullan --- src/java.base/share/classes/java/util/Properties.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/util/Properties.java b/src/java.base/share/classes/java/util/Properties.java index 6e02c3f5a238..b03c683180f7 100644 --- a/src/java.base/share/classes/java/util/Properties.java +++ b/src/java.base/share/classes/java/util/Properties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,8 +239,8 @@ public synchronized Object setProperty(String key, String value) { * Properties are processed in terms of lines. There are two * kinds of lines, natural lines and logical lines. * A natural line is defined as a line of - * characters that is terminated either by a set of line terminator - * characters ({@code \n} or {@code \r} or {@code \r\n}) + * characters that is terminated either by a line terminator + * sequence ({@code \n}, {@code \r}, or {@code \r\n}) * or by the end of the stream. A natural line may be either a blank line, * a comment line, or hold all or some of a key-element pair. A logical * line holds all the data of a key-element pair, which may be spread @@ -266,7 +266,7 @@ public synchronized Object setProperty(String key, String value) { *

      * If a logical line is spread across several natural lines, the * backslash escaping the line terminator sequence, the line - * terminator sequence, and any white space at the start of the + * terminator sequence itself, and any white space at the start of the * following line have no effect on the key or element values. * The remainder of the discussion of key and element parsing * (when loading) will assume all the characters constituting From 06f7bcd43d3ecfef325ca45e58026e00460fe09d Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Fri, 28 Aug 2026 18:22:17 +0000 Subject: [PATCH 140/223] 8389844: VectorAPI: VectorOperators.ZOMO specifies "Integral only", inconsistency between spec vs impl Reviewed-by: psandoz --- .../jdk/incubator/vector/DoubleVector.java | 10 +- .../jdk/incubator/vector/Float16Vector.java | 10 +- .../jdk/incubator/vector/FloatVector.java | 10 +- .../incubator/vector/X-Vector.java.template | 8 +- .../VectorLanewiseOpCompatibleWithTest.java | 159 ++++++++++++++++++ 5 files changed, 169 insertions(+), 28 deletions(-) create mode 100644 test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index be8651be3ffb..bda32bed969e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -680,10 +680,7 @@ final DoubleVector broadcastTemplate(long e) { final DoubleVector lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return unaryMathOp(op); } } @@ -708,10 +705,7 @@ DoubleVector lanewiseTemplate(VectorOperators.Unary op, VectorMask m) { m.check(maskClass, this); if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0, m)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return blend(unaryMathOp(op), m); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java index 18534d91d54c..708ded947d55 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java @@ -766,10 +766,7 @@ final Float16Vector broadcastTemplate(long e) { final Float16Vector lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return unaryMathOp(op); } } @@ -794,10 +791,7 @@ Float16Vector lanewiseTemplate(VectorOperators.Unary op, VectorMask m) { m.check(maskClass, this); if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0, m)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return blend(unaryMathOp(op), m); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 929c0a83b55f..775e939de2bf 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -680,10 +680,7 @@ final FloatVector broadcastTemplate(long e) { final FloatVector lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return unaryMathOp(op); } } @@ -708,10 +705,7 @@ FloatVector lanewiseTemplate(VectorOperators.Unary op, VectorMask m) { m.check(maskClass, this); if (opKind(op, VO_SPECIAL)) { - if (op == ZOMO) { - return blend(broadcast(-1), compare(NE, 0, m)); - } - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return blend(unaryMathOp(op), m); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index c593f6edfe6c..bfc8ce3dfeaa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -843,16 +843,16 @@ public abstract sealed class $abstractvectortype$ extends AbstractVector<$Boxtyp final $abstractvectortype$ lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { +#if[BITWISE] if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } -#if[BITWISE] else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } #end[BITWISE] #if[FP] - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return unaryMathOp(op); } #end[FP] @@ -878,16 +878,16 @@ public abstract sealed class $abstractvectortype$ extends AbstractVector<$Boxtyp VectorMask<$Boxtype$> m) { m.check(maskClass, this); if (opKind(op, VO_SPECIAL)) { +#if[BITWISE] if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } -#if[BITWISE] else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } #end[BITWISE] #if[FP] - else if (opKind(op, VO_MATHLIB)) { + if (opKind(op, VO_MATHLIB)) { return blend(unaryMathOp(op), m); } #end[FP] diff --git a/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java b/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java new file mode 100644 index 000000000000..5c12554c643e --- /dev/null +++ b/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import jdk.incubator.vector.Float16; +import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorMask; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorShape; +import jdk.incubator.vector.VectorSpecies; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8389844 + * @modules jdk.incubator.vector + * @run testng VectorLanewiseOpCompatibleWithTest + */ + +public class VectorLanewiseOpCompatibleWithTest { + private static final List> ELEMENT_TYPES = List.of( + byte.class, + short.class, + int.class, + long.class, + Float16.class, + float.class, + double.class); + + private static final List OPERATORS = vectorOperators(); + + private static List vectorOperators() { + List operators = new ArrayList<>(); + for (var field : VectorOperators.class.getFields()) { + if (Modifier.isStatic(field.getModifiers()) && + VectorOperators.Operator.class.isAssignableFrom(field.getType())) { + try { + operators.add((VectorOperators.Operator) field.get(null)); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + } + operators.sort(Comparator.comparing(VectorOperators.Operator::name)); + return List.copyOf(operators); + } + + @DataProvider + public Object[][] unsupportedOperatorProvider() { + return operatorProvider(false); + } + + @DataProvider + public Object[][] supportedOperatorProvider() { + return operatorProvider(true); + } + + private static Object[][] operatorProvider(boolean compatible) { + return ELEMENT_TYPES.stream() + .flatMap(elementType -> Arrays.stream(VectorShape.values()) + .map(shape -> VectorSpecies.of(elementType, shape))) + .flatMap(species -> OPERATORS.stream() + .filter(op -> op instanceof VectorOperators.Unary || + op instanceof VectorOperators.Binary || + op instanceof VectorOperators.Ternary) + // These operators are more restrictive, exclude for now. + .filter(op -> op != VectorOperators.COMPRESS_BITS && + op != VectorOperators.EXPAND_BITS) + .filter(op -> op.compatibleWith(species.elementType()) == compatible) + .map(op -> new Object[] {species, op})) + .toArray(Object[][]::new); + } + + @Test(dataProvider = "unsupportedOperatorProvider") + public void testUnsupportedOperator(VectorSpecies species, + VectorOperators.Operator op) { + Vector vector = species.zero(); + VectorMask mask = species.maskAll(false); + + switch (op) { + case VectorOperators.Unary unary -> { + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(unary)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(unary, mask)); + } + case VectorOperators.Binary binary -> { + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(binary, vector)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(binary, 0L)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(binary, vector, mask)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(binary, 0L, mask)); + } + case VectorOperators.Ternary ternary -> { + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(ternary, vector, vector)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.lanewise(ternary, vector, vector, mask)); + } + default -> throw new AssertionError("Not a lanewise operator: " + op); + } + } + + @Test(dataProvider = "supportedOperatorProvider") + public void testSupportedOperator(VectorSpecies species, + VectorOperators.Operator op) { + Vector vector = species.zero().broadcast(1L); + VectorMask mask = species.maskAll(true); + + switch (op) { + case VectorOperators.Unary unary -> { + vector.lanewise(unary); + vector.lanewise(unary, mask); + } + case VectorOperators.Binary binary -> { + vector.lanewise(binary, vector); + vector.lanewise(binary, 1L); + vector.lanewise(binary, vector, mask); + vector.lanewise(binary, 1L, mask); + } + case VectorOperators.Ternary ternary -> { + vector.lanewise(ternary, vector, vector); + vector.lanewise(ternary, vector, vector, mask); + } + default -> throw new AssertionError("Not a lanewise operator: " + op); + } + } +} From a523f7f2875c82aac7a742d1398e40086336bfa9 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 28 Aug 2026 22:06:59 +0000 Subject: [PATCH 141/223] 8384108: Test Object.clone on a value object read from a flattened field Reviewed-by: lmesnik, liach --- test/jdk/java/lang/Object/ValueObjects.java | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/jdk/java/lang/Object/ValueObjects.java b/test/jdk/java/lang/Object/ValueObjects.java index f84cee73a99f..50122d1a401d 100644 --- a/test/jdk/java/lang/Object/ValueObjects.java +++ b/test/jdk/java/lang/Object/ValueObjects.java @@ -74,6 +74,32 @@ protected V clone() throws CloneNotSupportedException { assertThrows(CloneNotSupportedException.class, obj::clone); } + /** + * Test the Object.clone method on a value object read from a flattened + * field. The read materializes the value from the embedded payload and + * clone returns it. + */ + @Test + void testCloneValueFromField() throws Exception { + value class V implements Cloneable { + int i; + V(int i) { this.i = i; } + @Override + protected V clone() throws CloneNotSupportedException { + return (V) super.clone(); + } + } + class Holder { + V v = new V(42); + } + var holder = new Holder(); + V read = holder.v; + V copy = read.clone(); + assertSame(read, copy); + assertEquals(42, copy.i); + assertSame(holder.v, holder.v.clone()); + } + /** * Test that the finalize method on a value class is not invoked by the GC. */ From e72d3393c9d31e18c37beb1010ad4ec06e1d4289 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Sat, 29 Aug 2026 03:14:46 +0000 Subject: [PATCH 142/223] 8391330: RISC-V: JSR166TestCase.java fails after JDK-8369828 Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 126 +++++++++++++++++- .../cpu/riscv/macroAssembler_riscv.cpp | 5 +- .../cpu/riscv/macroAssembler_riscv.hpp | 2 +- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 8 +- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 20 +-- src/hotspot/cpu/riscv/relocInfo_riscv.cpp | 2 +- 6 files changed, 140 insertions(+), 23 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index b657c1f108dd..a689107493b1 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -514,20 +514,138 @@ class Assembler : public AbstractAssembler { rdy = 0b111, // in instruction's rm field, selects dynamic rounding mode.In Rounding Mode register, Invalid. }; + // Efficient reading and writing of unaligned data in platform-specific byte ordering + // RISC-V needs to check for alignment. + + static inline u2 get_native_u2(address p) { + if ((intptr_t(p) & 1) == 0) { + return *(u2*)p; + } else { + return ((u2)(p[1]) << 8) | + ((u2)(p[0])); + } + } + + static inline u4 get_native_u4(address p) { + switch (intptr_t(p) & 3) { + case 0: + return *(u4*)p; + + case 2: + return ((u4)(((u2*)p)[1]) << 16) | + ((u4)(((u2*)p)[0])); + + default: + return ((u4)(p[3]) << 24) | + ((u4)(p[2]) << 16) | + ((u4)(p[1]) << 8) | + ((u4)(p[0])); + } + } + + static inline u8 get_native_u8(address p) { + switch (intptr_t(p) & 7) { + case 0: + return *(u8*)p; + + case 4: + return ((u8)(((u4*)p)[1]) << 32) | + ((u8)(((u4*)p)[0])); + + case 2: + case 6: + return ((u8)(((u2*)p)[3]) << 48) | + ((u8)(((u2*)p)[2]) << 32) | + ((u8)(((u2*)p)[1]) << 16) | + ((u8)(((u2*)p)[0])); + + default: + return ((u8)(p[7]) << 56) | + ((u8)(p[6]) << 48) | + ((u8)(p[5]) << 40) | + ((u8)(p[4]) << 32) | + ((u8)(p[3]) << 24) | + ((u8)(p[2]) << 16) | + ((u8)(p[1]) << 8) | + ((u8)(p[0])); + } + } + + static inline void put_native_u2(address p, u2 x) { + if ((intptr_t(p) & 1) == 0) { + *(u2*)p = x; + } else { + p[1] = x >> 8; + p[0] = x; + } + } + + static inline void put_native_u4(address p, u4 x) { + switch (intptr_t(p) & 3) { + case 0: + *(u4*)p = x; + break; + + case 2: + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + static inline void put_native_u8(address p, u8 x) { + switch (intptr_t(p) & 7) { + case 0: + *(u8*)p = x; + break; + + case 4: + ((u4*)p)[1] = x >> 32; + ((u4*)p)[0] = x; + break; + + case 2: + case 6: + ((u2*)p)[3] = x >> 48; + ((u2*)p)[2] = x >> 32; + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: + ((u1*)p)[7] = x >> 56; + ((u1*)p)[6] = x >> 48; + ((u1*)p)[5] = x >> 40; + ((u1*)p)[4] = x >> 32; + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + // handle unaligned access static inline uint16_t ld_c_instr(address addr) { - return Bytes::get_native_u2(addr); + return get_native_u2(addr); } static inline void sd_c_instr(address addr, uint16_t c_instr) { - Bytes::put_native_u2(addr, c_instr); + put_native_u2(addr, c_instr); } // handle unaligned access static inline uint32_t ld_instr(address addr) { - return Bytes::get_native_u4(addr); + return get_native_u4(addr); } static inline void sd_instr(address addr, uint32_t instr) { - Bytes::put_native_u4(addr, instr); + put_native_u4(addr, instr); } static inline uint32_t extract(uint32_t val, unsigned msb, unsigned lsb) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 154e3ea337fa..fdb2ee314b37 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -162,8 +162,7 @@ uint32_t MacroAssembler::get_membar_kind(address addr) { assert_cond(addr != nullptr); assert(is_membar(addr), "no membar found"); - uint32_t insn = Bytes::get_native_u4(addr); - + uint32_t insn = Assembler::ld_instr(addr); uint32_t predecessor = Assembler::extract(insn, 27, 24); uint32_t successor = Assembler::extract(insn, 23, 20); @@ -179,7 +178,7 @@ void MacroAssembler::set_membar_kind(address addr, uint32_t order_kind) { MacroAssembler::membar_mask_to_pred_succ(order_kind, predecessor, successor); - uint32_t insn = Bytes::get_native_u4(addr); + uint32_t insn = Assembler::ld_instr(addr); address pInsn = (address) &insn; Assembler::patch(pInsn, 27, 24, predecessor); Assembler::patch(pInsn, 23, 20, successor); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 9af9fad06d08..00003c902ef2 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1842,7 +1842,7 @@ class MacroAssembler: public Assembler { static bool is_pc_relative_at(address branch); static bool is_membar(address addr) { - return (Bytes::get_native_u4(addr) & 0x7f) == 0b1111 && extract_funct3(addr) == 0; + return (Assembler::ld_instr(addr) & 0x7f) == 0b1111 && extract_funct3(addr) == 0; } static uint32_t get_membar_kind(address addr); static void set_membar_kind(address addr, uint32_t order_kind); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 5d1cac72ade2..6f51395898a3 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -234,7 +234,7 @@ void NativeMovConstReg::verify() { intptr_t NativeMovConstReg::data() const { address addr = MacroAssembler::target_addr_for_insn(instruction_address()); if (maybe_cpool_ref(instruction_address())) { - return Bytes::get_native_u8(addr); + return MacroAssembler::get_native_u8(addr); } else { return (intptr_t)addr; } @@ -243,7 +243,7 @@ intptr_t NativeMovConstReg::data() const { void NativeMovConstReg::set_data(intptr_t x) { if (maybe_cpool_ref(instruction_address())) { address addr = MacroAssembler::target_addr_for_insn(instruction_address()); - Bytes::put_native_u8(addr, x); + MacroAssembler::put_native_u8(addr, x); } else { // Store x into the instruction stream. MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)x); @@ -259,11 +259,11 @@ void NativeMovConstReg::set_data(intptr_t x) { while (iter.next()) { if (iter.type() == relocInfo::oop_type) { oop* oop_addr = iter.oop_reloc()->oop_addr(); - Bytes::put_native_u8((address)oop_addr, x); + MacroAssembler::put_native_u8((address)oop_addr, x); break; } else if (iter.type() == relocInfo::metadata_type) { Metadata** metadata_addr = iter.metadata_reloc()->metadata_addr(); - Bytes::put_native_u8((address)metadata_addr, x); + MacroAssembler::put_native_u8((address)metadata_addr, x); break; } } diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index b28e33759b2f..90f32c9b25db 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -78,19 +78,19 @@ class NativeInstruction { protected: address addr_at(int offset) const { return address(this) + offset; } - jint int_at(int offset) const { return (jint) Bytes::get_native_u4(addr_at(offset)); } - juint uint_at(int offset) const { return Bytes::get_native_u4(addr_at(offset)); } - address ptr_at(int offset) const { return (address) Bytes::get_native_u8(addr_at(offset)); } - oop oop_at(int offset) const { return cast_to_oop(Bytes::get_native_u8(addr_at(offset))); } + jint int_at(int offset) const { return (jint) MacroAssembler::get_native_u4(addr_at(offset)); } + juint uint_at(int offset) const { return MacroAssembler::get_native_u4(addr_at(offset)); } + address ptr_at(int offset) const { return (address) MacroAssembler::get_native_u8(addr_at(offset)); } + oop oop_at(int offset) const { return cast_to_oop(MacroAssembler::get_native_u8(addr_at(offset))); } - void set_int_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } - void set_uint_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } - void set_ptr_at(int offset, address ptr) { Bytes::put_native_u8(addr_at(offset), (u8)ptr); } - void set_oop_at(int offset, oop o) { Bytes::put_native_u8(addr_at(offset), cast_from_oop(o)); } + void set_int_at(int offset, jint i) { MacroAssembler::put_native_u4(addr_at(offset), i); } + void set_uint_at(int offset, juint i) { MacroAssembler::put_native_u4(addr_at(offset), i); } + void set_ptr_at(int offset, address ptr) { MacroAssembler::put_native_u8(addr_at(offset), (u8)ptr); } + void set_oop_at(int offset, oop o) { MacroAssembler::put_native_u8(addr_at(offset), cast_from_oop(o)); } - static void set_data64_at(address dest, uint64_t data) { Bytes::put_native_u8(dest, (u8)data); } - static uint64_t get_data64_at(address src) { return Bytes::get_native_u8(src); } + static void set_data64_at(address dest, uint64_t data) { MacroAssembler::put_native_u8(dest, (u8)data); } + static uint64_t get_data64_at(address src) { return MacroAssembler::get_native_u8(src); } public: inline friend NativeInstruction* nativeInstruction_at(address addr); diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp index ccd8b8919969..09264327516e 100644 --- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -44,7 +44,7 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { if (MacroAssembler::is_load_pc_relative_at(addr())) { address constptr = (address)code()->oop_addr_at(reloc->oop_index()); bytes = MacroAssembler::pd_patch_instruction_size(addr(), constptr); - assert((address)Bytes::get_native_u8(constptr) == x, "error in oop relocation"); + assert((address)MacroAssembler::get_native_u8(constptr) == x, "error in oop relocation"); } else { bytes = MacroAssembler::patch_oop(addr(), x); } From 5962d86603a98a0f83aad6fcd6e9dcf90182504e Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Sat, 29 Aug 2026 08:32:29 +0000 Subject: [PATCH 143/223] 8391333: RISC-V: Use zext.h and zext.w for AndL with 16-bit and 32-bit mask Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/riscv.ad | 10 ++++++++++ src/hotspot/cpu/riscv/riscv_b.ad | 32 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 033e4a4222e0..e87a11523c5c 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2850,6 +2850,16 @@ operand immIpowerOf2() %{ interface(CONST_INTER); %} +// Long Immediate: low 16-bit mask +operand immL_16bits() +%{ + predicate(n->get_long() == 0xFFFFL); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Long Immediate: low 32-bit mask operand immL_32bits() %{ diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad index a13efa96fc16..cf61b1d43a6e 100644 --- a/src/hotspot/cpu/riscv/riscv_b.ad +++ b/src/hotspot/cpu/riscv/riscv_b.ad @@ -183,7 +183,37 @@ instruct convI2UL_reg_reg_b(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) %{ __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); %} - ins_pipe(ialu_reg_shift); + ins_pipe(ialu_reg); +%} + +// And with a low 16-bit mask +instruct andL_16bits_b(iRegLNoSp dst, iRegL src, immL_16bits mask) %{ + predicate(UseZbb); + match(Set dst (AndL src mask)); + + format %{ "zext.h $dst, $src\t#@andL_16bits_b" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ zext_h(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// And with a low 32-bit mask +instruct andL_32bits_b(iRegLNoSp dst, iRegL src, immL_32bits mask) %{ + predicate(UseZba); + match(Set dst (AndL src mask)); + + format %{ "zext.w $dst, $src\t#@andL_32bits_b" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); %} // BSWAP instructions From f88e6aeb9a74cbb62ca49895d1d24a8a86f74952 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Sat, 29 Aug 2026 16:19:37 +0000 Subject: [PATCH 144/223] 8391075: 'jfr assemble' doesn't handle unfinished files Reviewed-by: mgronlun --- .../jfr/internal/consumer/ChunkHeader.java | 6 +- .../jfr/internal/consumer/RecordingInput.java | 4 +- .../jdk/jfr/internal/tool/Assemble.java | 34 +++++++- .../jdk/jfr/internal/tool/HeaderData.java | 85 +++++++++++++++++++ test/jdk/jdk/jfr/tool/TestAssemble.java | 51 +++++++++-- 5 files changed, 165 insertions(+), 15 deletions(-) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/tool/HeaderData.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java index 1fbe07803c75..4381da513def 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,10 @@ public final class ChunkHeader { public static final long HEADER_SIZE = 68; - static final byte UPDATING_CHUNK_HEADER = (byte) 255; + public static final byte UPDATING_CHUNK_HEADER = (byte) 255; public static final long CHUNK_SIZE_POSITION = 8; static final long DURATION_NANOS_POSITION = 40; - static final long FILE_STATE_POSITION = 64; + public static final long FILE_STATE_POSITION = 64; static final long FLAG_BYTE_POSITION = 67; static final long METADATA_TYPE_ID = 0; static final byte[] FILE_MAGIC = { 'F', 'L', 'R', '\0' }; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java index 001bd39896e3..03aa9166ed58 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java @@ -98,7 +98,7 @@ public RecordingInput(File f) throws IOException { this(f, DEFAULT_BLOCK_SIZE); } - void positionPhysical(long position) throws IOException { + public void positionPhysical(long position) throws IOException { file.seek(position); } @@ -110,7 +110,7 @@ long readPhysicalLong() throws IOException { return file.readLong(); } - void readPhysicalFully(byte[] dest, int offset, int length) throws IOException { + public void readPhysicalFully(byte[] dest, int offset, int length) throws IOException { file.readFully(dest, offset, length); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java index 75169e816a99..36eff5b41064 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,16 +28,20 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.List; +import jdk.jfr.internal.consumer.ChunkHeader; +import jdk.jfr.internal.consumer.RecordingInput; import jdk.jfr.internal.util.UserDataException; import jdk.jfr.internal.util.UserSyntaxException; @@ -111,14 +115,36 @@ private List listJFRFiles(Path path) throws UserDataException { } private void transferTo(List sourceFiles, Path output, FileChannel out) throws UserDataException { - long pos = 0; for (Path p : sourceFiles) { + long pos = 0; + long rem = 0; + try (RecordingInput input = new RecordingInput(p.toFile())) { + HeaderData hd = HeaderData.read(input); + if (hd == null) { + println("Skipping recording chunk that is being updated " + p ); + continue; + } + if (hd.finished()) { + rem = Files.size(p); + } else { + hd.markFinished(); + hd.write(out); + println("Truncating unfinished recording chunk " + p); + rem = hd.size() - ChunkHeader.HEADER_SIZE; + pos = ChunkHeader.HEADER_SIZE; + } + } catch (IOException e) { + println("Skipping recording chunk " + p + " due to: " + e.getMessage()); + continue; + } println(" " + p.toString()); try (FileChannel sourceChannel = FileChannel.open(p)) { - long rem = Files.size(p); while (rem > 0) { long n = Math.min(rem, 1024 * 1024); - long w = out.transferFrom(sourceChannel, pos, n); + long w = sourceChannel.transferTo(pos, n, out); + if (w == 0) { + throw new IOException("Could not transfer remaining bytes"); + } pos += w; rem -= w; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/HeaderData.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/HeaderData.java new file mode 100644 index 000000000000..79d090f34a41 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/HeaderData.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal.tool; + +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.ByteBuffer; +import jdk.jfr.internal.consumer.ChunkHeader; +import jdk.jfr.internal.consumer.RecordingInput; + +final class HeaderData { + private static int FILE_STATE_POSITION = (int) ChunkHeader.FILE_STATE_POSITION; + private static int CHUNK_SIZE_POSITION = (int) ChunkHeader.CHUNK_SIZE_POSITION; + private static int HEADER_SIZE = (int) ChunkHeader.HEADER_SIZE; + + private final ByteBuffer buffer; + + HeaderData(byte[] bytes) { + buffer = ByteBuffer.wrap(bytes); + } + + boolean finished() { + return buffer.get(FILE_STATE_POSITION) == 0; + } + + long size() { + return buffer.getLong(CHUNK_SIZE_POSITION); + } + + void markFinished() { + buffer.put(FILE_STATE_POSITION, (byte) 0); + } + + void write(FileChannel out) throws IOException { + while (buffer.hasRemaining()) { + out.write(buffer); + } + } + + static HeaderData read(RecordingInput input) throws IOException { + byte[] first = new byte[HEADER_SIZE]; + byte[] second = new byte[HEADER_SIZE]; + while (true) { + while (true) { + input.positionPhysical(0); + input.readPhysicalFully(first, 0, first.length); + if (first[FILE_STATE_POSITION] != ChunkHeader.UPDATING_CHUNK_HEADER) { + break; + } + try { + input.pollWait(); + } catch (IOException ioe) { + return null; + } + } + input.positionPhysical(0); + input.readPhysicalFully(second, 0, second.length); + if (first[FILE_STATE_POSITION] == second[FILE_STATE_POSITION]) { + return new HeaderData(first); + } + } + } +} \ No newline at end of file diff --git a/test/jdk/jdk/jfr/tool/TestAssemble.java b/test/jdk/jdk/jfr/tool/TestAssemble.java index 43c862d8999a..4aec19342e16 100644 --- a/test/jdk/jdk/jfr/tool/TestAssemble.java +++ b/test/jdk/jdk/jfr/tool/TestAssemble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,11 @@ import java.io.FileWriter; import java.io.IOException; +import java.io.RandomAccessFile; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import jdk.jfr.Event; import jdk.jfr.Name; @@ -69,14 +71,16 @@ public static void main(String[] args) throws Throwable { r.stop(); recordings[i] = r; } - Path dir = Paths.get("reconstruction-parts"); + Path dir = Paths.get("reconstruction-parts").toAbsolutePath(); Files.createDirectories(dir); long expectedCount = 0; + Path[] files = new Path[RECORDING_COUNT]; for (int i = 0; i < RECORDING_COUNT; i++) { - Path tmp = dir.resolve("chunk-part-" + i + ".jfr"); - recordings[i].dump(tmp); - expectedCount += countEventInRecording(tmp); + Path file = dir.resolve("chunk-part-" + i + ".jfr"); + recordings[i].dump(file); + expectedCount += countEventInRecording(file); + files[i] = file; } Path repository = Repository.getRepository().getRepositoryPath(); @@ -112,15 +116,50 @@ public static void main(String[] args) throws Throwable { output = ExecuteHelper.jfr("assemble", directory, destination); System.out.println(output.getOutput()); output.shouldContain("Finished."); - long reconstructedCount = countEventInRecording(destinationPath); Asserts.assertEquals(expectedCount, reconstructedCount); + Files.delete(destinationPath); + + // Test unfinished and updated + writeUnfinished(files[1]); + writeUpdating(files[2]); + output = ExecuteHelper.jfr("assemble", dir.toString(), destination); + System.out.println(output.getOutput()); + output.shouldContain("Skipping"); + output.shouldContain("Truncating"); + reconstructedCount = countEventInRecording(destinationPath); + Asserts.assertEquals(RECORDING_COUNT - 1L, reconstructedCount); + Files.delete(destinationPath); + // Cleanup for (int i = 0; i < RECORDING_COUNT; i++) { recordings[i].close(); } } + private static void writeUpdating(Path path) throws IOException { + try (RandomAccessFile raf = new RandomAccessFile(path.toFile(), "rw")) { + raf.seek(64); // file state position + raf.write(255); // means the JVM is currently modifying header + appendJunk(raf); + } + } + + private static void writeUnfinished(Path path) throws IOException { + try (RandomAccessFile raf = new RandomAccessFile(path.toFile(), "rw")) { + raf.seek(64); // file state position + raf.write(42); // generation 42 (not finished) + appendJunk(raf); + } + } + + private static void appendJunk(RandomAccessFile raf) throws IOException { + byte[] junk = new byte[131072]; + Arrays.fill(junk, (byte)42); + raf.seek(raf.length()); + raf.write(junk); + } + private static long countEventInRecording(Path file) throws IOException { Integer lastId = -1; try (RecordingFile rf = new RecordingFile(file)) { From 84c83ed5efa354de7c6403e215dd080ae9eb9449 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 31 Aug 2026 01:20:25 +0000 Subject: [PATCH 145/223] 8388884: [macOS] Swing Aqua L&F text components enable drag by default Reviewed-by: azvegint, prr, serb --- .../com/apple/laf/AquaEditorPaneUI.java | 21 ++- .../classes/com/apple/laf/AquaTextAreaUI.java | 21 ++- .../com/apple/laf/AquaTextFieldUI.java | 24 +-- .../classes/com/apple/laf/AquaTextPaneUI.java | 23 ++- .../share/classes/javax/swing/JComponent.java | 11 ++ .../javax/swing/plaf/basic/BasicTextUI.java | 1 + .../javax/swing/text/JTextComponent.java | 16 ++ .../classes/sun/swing/SwingAccessor.java | 2 + .../TextComponentDragEnabledTest.java | 166 ++++++++++++++++++ 9 files changed, 249 insertions(+), 36 deletions(-) create mode 100644 test/jdk/javax/swing/text/JTextComponent/TextComponentDragEnabledTest.java diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaEditorPaneUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaEditorPaneUI.java index ba58f505b311..9d6eaadec519 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaEditorPaneUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,25 +33,30 @@ import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.text.*; +import sun.swing.SwingAccessor; + public final class AquaEditorPaneUI extends BasicEditorPaneUI { public static ComponentUI createUI(final JComponent c){ return new AquaEditorPaneUI(); } - boolean oldDragState = false; + private boolean oldDragState; + @Override protected void installDefaults(){ + oldDragState = getComponent().getDragEnabled(); super.installDefaults(); - if(!GraphicsEnvironment.isHeadless()){ - oldDragState = getComponent().getDragEnabled(); - getComponent().setDragEnabled(true); + if (!GraphicsEnvironment.isHeadless()) { + LookAndFeel.installProperty(getComponent(), "dragEnabled", true); } } @Override - protected void uninstallDefaults(){ - if(!GraphicsEnvironment.isHeadless()){ - getComponent().setDragEnabled(oldDragState); + protected void uninstallDefaults() { + if (!SwingAccessor.getJTextComponentAccessor() + .isDragEnabledSet(getComponent())) { + LookAndFeel.installProperty(getComponent(), "dragEnabled", + oldDragState); } super.uninstallDefaults(); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextAreaUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextAreaUI.java index d968412da761..8aa7f9c008cd 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextAreaUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.text.*; +import sun.swing.SwingAccessor; + public final class AquaTextAreaUI extends BasicTextAreaUI { public static ComponentUI createUI(final JComponent c) { return new AquaTextAreaUI(); @@ -67,20 +69,23 @@ protected void uninstallListeners() { super.uninstallListeners(); } - boolean oldDragState = false; + private boolean oldDragState; + @Override - protected void installDefaults() { + protected void installDefaults(){ + oldDragState = getComponent().getDragEnabled(); + super.installDefaults(); if (!GraphicsEnvironment.isHeadless()) { - oldDragState = getComponent().getDragEnabled(); - getComponent().setDragEnabled(true); + LookAndFeel.installProperty(getComponent(), "dragEnabled", true); } - super.installDefaults(); } @Override protected void uninstallDefaults() { - if (!GraphicsEnvironment.isHeadless()) { - getComponent().setDragEnabled(oldDragState); + if (!SwingAccessor.getJTextComponentAccessor() + .isDragEnabledSet(getComponent())) { + LookAndFeel.installProperty(getComponent(), "dragEnabled", + oldDragState); } super.uninstallDefaults(); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldUI.java index e3287ccbce93..d1b09c459e03 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.text.*; +import sun.swing.SwingAccessor; import com.apple.laf.AquaUtils.JComponentPainter; public class AquaTextFieldUI extends BasicTextFieldUI { @@ -68,24 +69,25 @@ protected void uninstallListeners() { super.uninstallListeners(); } - boolean oldDragState = false; + private boolean oldDragState; + @Override - protected void installDefaults() { + protected void installDefaults(){ + oldDragState = getComponent().getDragEnabled(); + super.installDefaults(); if (!GraphicsEnvironment.isHeadless()) { - oldDragState = getComponent().getDragEnabled(); - getComponent().setDragEnabled(true); + LookAndFeel.installProperty(getComponent(), "dragEnabled", true); } - - super.installDefaults(); } @Override protected void uninstallDefaults() { - super.uninstallDefaults(); - - if (!GraphicsEnvironment.isHeadless()) { - getComponent().setDragEnabled(oldDragState); + if (!SwingAccessor.getJTextComponentAccessor() + .isDragEnabledSet(getComponent())) { + LookAndFeel.installProperty(getComponent(), "dragEnabled", + oldDragState); } + super.uninstallDefaults(); } // Install a default keypress action which handles Cmd and Option keys diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPaneUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPaneUI.java index 571cbf6369a2..d8d8d5520195 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPaneUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.text.*; +import sun.swing.SwingAccessor; + //[3663467] moved it to sublcass from BasicEditorPaneUI to BasicTextPaneUI. (vm) public final class AquaTextPaneUI extends BasicTextPaneUI { public static ComponentUI createUI(final JComponent c) { @@ -63,25 +65,28 @@ protected void uninstallListeners() { super.uninstallListeners(); } - boolean oldDragState = false; + private boolean oldDragState; + @Override - protected void installDefaults() { - final JTextComponent c = getComponent(); + protected void installDefaults(){ + oldDragState = getComponent().getDragEnabled(); + super.installDefaults(); if (!GraphicsEnvironment.isHeadless()) { - oldDragState = c.getDragEnabled(); - c.setDragEnabled(true); + LookAndFeel.installProperty(getComponent(), "dragEnabled", true); } - super.installDefaults(); } @Override protected void uninstallDefaults() { - if (!GraphicsEnvironment.isHeadless()) { - getComponent().setDragEnabled(oldDragState); + if (!SwingAccessor.getJTextComponentAccessor() + .isDragEnabledSet(getComponent())) { + LookAndFeel.installProperty(getComponent(), "dragEnabled", + oldDragState); } super.uninstallDefaults(); } + // Install a default keypress action which handles Cmd and Option keys // properly @Override diff --git a/src/java.desktop/share/classes/javax/swing/JComponent.java b/src/java.desktop/share/classes/javax/swing/JComponent.java index 943bfc946d70..65be77430ce9 100644 --- a/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -36,6 +36,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.KeyboardFocusManager; import java.awt.Point; @@ -90,6 +91,7 @@ import javax.swing.event.AncestorListener; import javax.swing.event.EventListenerList; import javax.swing.plaf.ComponentUI; +import javax.swing.text.JTextComponent; import sun.awt.AWTAccessor; import sun.awt.SunToolkit; @@ -4192,6 +4194,15 @@ void setUIProperty(String propertyName, Object value) { BACKWARD_TRAVERSAL_KEYS, strokeSet); } + } else if ("dragEnabled".equals(propertyName) + && this instanceof JTextComponent textComponent) { + if (!GraphicsEnvironment.isHeadless()) { + var accessor = SwingAccessor.getJTextComponentAccessor(); + if (!accessor.isDragEnabledSet(textComponent)) { + accessor.setDragEnabledUIResource(textComponent, + (Boolean) value); + } + } } else { throw new IllegalArgumentException("property \""+ propertyName+ "\" cannot be set using this method"); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java index d144b5b7240d..e29b05c6f058 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java @@ -355,6 +355,7 @@ protected void installDefaults() editor.setMargin(UIManager.getInsets(prefix + ".margin")); } + LookAndFeel.installProperty(editor, "dragEnabled", false); updateCursor(); } diff --git a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index f81ba9d66c2d..f9f1303bfb08 100644 --- a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -312,6 +312,7 @@ public JTextComponent() { addFocusListener(caretEvent); setEditable(true); setDragEnabled(false); + dragEnabledSet = false; setLayout(null); // layout is managed by View hierarchy updateUI(); } @@ -681,6 +682,12 @@ public void setKeymap(Keymap map) { public void setDragEnabled(boolean b) { checkDragEnabled(b); dragEnabled = b; + dragEnabledSet = true; + } + + private void setDragEnabledUIResource(boolean b) { + checkDragEnabled(b); + dragEnabled = b; } private static void checkDragEnabled(boolean b) { @@ -768,6 +775,13 @@ public Object setDropLocation(JTextComponent textComp, { return textComp.setDropLocation(location, state, forDrop); } + public boolean isDragEnabledSet(JTextComponent textComp) { + return textComp.dragEnabledSet; + } + public void setDragEnabledUIResource(JTextComponent textComp, + boolean value) { + textComp.setDragEnabledUIResource(value); + } }); } @@ -3801,6 +3815,7 @@ private void readObject(ObjectInputStream s) boolean newDragEnabled = f.get("dragEnabled", false); checkDragEnabled(newDragEnabled); dragEnabled = newDragEnabled; + dragEnabledSet = f.get("dragEnabledSet", false); DropMode newDropMode = (DropMode) f.get("dropMode", DropMode.USE_SELECTION); checkDropMode(newDropMode); @@ -3869,6 +3884,7 @@ private void readObject(ObjectInputStream s) private Insets margin; private char focusAccelerator; private boolean dragEnabled; + private boolean dragEnabledSet; /** * The drop mode for this component. diff --git a/src/java.desktop/share/classes/sun/swing/SwingAccessor.java b/src/java.desktop/share/classes/sun/swing/SwingAccessor.java index 563cc038ae96..3fab33483a6e 100644 --- a/src/java.desktop/share/classes/sun/swing/SwingAccessor.java +++ b/src/java.desktop/share/classes/sun/swing/SwingAccessor.java @@ -87,6 +87,8 @@ public interface JTextComponentAccessor { */ Object setDropLocation(JTextComponent textComp, TransferHandler.DropLocation location, Object state, boolean forDrop); + boolean isDragEnabledSet(JTextComponent textComp); + void setDragEnabledUIResource(JTextComponent textComp, boolean value); } /** diff --git a/test/jdk/javax/swing/text/JTextComponent/TextComponentDragEnabledTest.java b/test/jdk/javax/swing/text/JTextComponent/TextComponentDragEnabledTest.java new file mode 100644 index 000000000000..a5f031a14e2b --- /dev/null +++ b/test/jdk/javax/swing/text/JTextComponent/TextComponentDragEnabledTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=headful + * @bug 8388884 + * @key headful + * @summary Checks dragEnabled defaults and explicit settings across installed L&Fs + * @run main TextComponentDragEnabledTest + */ + +/* + * @test id=headless + * @bug 8388884 + * @summary Checks dragEnabled defaults and explicit settings across installed L&Fs + * @run main/othervm -Djava.awt.headless=true TextComponentDragEnabledTest + */ + +import java.util.List; +import java.util.function.Supplier; + +import java.awt.GraphicsEnvironment; + +import javax.swing.JEditorPane; +import javax.swing.JFormattedTextField; +import javax.swing.JPasswordField; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.JTextPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.text.JTextComponent; +import javax.swing.UnsupportedLookAndFeelException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class TextComponentDragEnabledTest { + + private static final String AQUA_LAF = "com.apple.laf.AquaLookAndFeel"; + + private static final List> TEXT_COMPONENTS = List.of( + JTextField::new, + JTextArea::new, + JTextPane::new, + JEditorPane::new, + JPasswordField::new, + JFormattedTextField::new + ); + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + try { + runTest(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + private static void runTest() throws Exception { + testDefaultsForAllLookAndFeels(); + if (!GraphicsEnvironment.isHeadless()) { + testExplicitSettingsForAllLookAndFeels(); + } + } + + private static void testDefaultsForAllLookAndFeels() + throws Exception { + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing L&F " + laf.getClassName()); + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException e) { + System.out.println("Skipping unsupported L&F: " + laf.getClassName()); + continue; + } + + for (Supplier supplier : TEXT_COMPONENTS) { + JTextComponent component = supplier.get(); + boolean expected = AQUA_LAF.equals(laf.getClassName()) + && !GraphicsEnvironment.isHeadless(); + checkDragEnabled(component, expected, + "new component under " + laf.getClassName()); + } + } + } + + private static void testExplicitSettingsForAllLookAndFeels() + throws Exception { + for (boolean expected : new boolean[] { false, true }) { + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + + for (Supplier supplier : TEXT_COMPONENTS) { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + JTextComponent component = supplier.get(); + component.setDragEnabled(expected); + + UIManager.setLookAndFeel(laf.getClassName()); + component.updateUI(); + + checkDragEnabled(component, expected, + "after switching to " + laf.getClassName()); + + testSerialization(component, expected); + } + } + } + } + + private static void testSerialization(JTextComponent component, boolean expected) throws Exception { + JTextComponent copy = serializeAndDeserialize(component); + checkDragEnabled(copy, expected, "after deserializing application value"); + } + + private static JTextComponent serializeAndDeserialize(JTextComponent component) + throws Exception { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + + try (ObjectOutputStream out = new ObjectOutputStream(bytes)) { + out.writeObject(component); + } + + try (ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(bytes.toByteArray()))) { + return (JTextComponent) in.readObject(); + } + } + + private static void checkDragEnabled(JTextComponent component, + boolean expected, + String msg) { + boolean actual = component.getDragEnabled(); + if (actual != expected) { + throw new RuntimeException(component.getClass().getName() + + ": " + msg + + "; expected dragEnabled=" + expected + + ", actual=" + actual); + } + } +} From 9ae4112121579fd3ad5a7fdb3bb3980accfae4fb Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 31 Aug 2026 05:33:09 +0000 Subject: [PATCH 146/223] 8387799: Infinite attempts of post-parse call devirtualization on nullable receiver Reviewed-by: kvn, vlivanov --- src/hotspot/share/opto/callnode.cpp | 11 +-- src/hotspot/share/opto/phaseX.cpp | 17 ----- .../TestLateInlineNullableReceiver.java | 73 +++++++++++++++++++ 3 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestLateInlineNullableReceiver.java diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index d32a824f2baf..ccfbb9f9a50a 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1561,6 +1561,9 @@ Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(IncrementalInlineVirtual, "required"); assert(cg->call_node() == this, "mismatch"); + Node* receiver_node = in(TypeFunc::Parms); + const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); + if (cg->callee_method() == nullptr) { // Recover symbolic info for method resolution. ciMethod* caller = jvms()->method(); @@ -1579,9 +1582,6 @@ Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - Node* receiver_node = in(TypeFunc::Parms); - const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); - int not_used3; bool call_does_dispatch; ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, @@ -1590,8 +1590,9 @@ Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { cg->set_callee_method(callee); } } - if (cg->callee_method() != nullptr) { - // Register for late inlining. + if (cg->callee_method() != nullptr && receiver_type != nullptr && !receiver_type->maybe_null()) { + // Only register for late inlining if the receiver is null-free because + // LateInlineVirtualCallGenerator::do_late_inline_check() rejects nullable receivers. register_for_late_inline(); // MH late inlining prepends to the list, so do the same } } else { diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 77c2fd27a50e..0a9a82a20063 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1909,23 +1909,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit // test/jdk/jdk/incubator/vector/VectorRuns.java // -XX:VerifyIterativeGVN=1110 - // CallDynamicJavaNode::Ideal, and I think also for CallStaticJavaNode::Ideal - // and possibly their subclasses. - // During late inlining it can call CallJavaNode::register_for_late_inline - // That means we do more rounds of late inlining, but might fail. - // Then we do IGVN again, and register the node again for late inlining. - // This creates an endless cycle. Everytime we try late inlining, we - // are also creating more nodes, especially SafePoint and MergeMem. - // These nodes are immediately rejected when the inlining fails in the - // do_late_inline_check, but they still grow the memory, until we hit - // the MemLimit and crash. - // The assumption here seems that CallDynamicJavaNode::Ideal does not get - // called repeatedly, and eventually we terminate. I fear this is not - // a great assumption to make. We should investigate more. - // - // Found with: - // compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-U - // -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 return; } diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateInlineNullableReceiver.java b/test/hotspot/jtreg/compiler/inlining/TestLateInlineNullableReceiver.java new file mode 100644 index 000000000000..bd6ce98658b9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestLateInlineNullableReceiver.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8387799 + * @summary Test that a nullable receiver is not endlessly retried for virtual late inlining + * @modules jdk.incubator.vector + * @library /test/lib + * @requires vm.compiler2.enabled + * @run main ${test.main.class} + * @run main/othervm -Xcomp + * -XX:CompileCommand=compileonly,${test.main.class}::test + * -XX:CompileCommand=delayinline,${test.main.class}::lateInlined + * ${test.main.class} + */ + +package compiler.inlining; + +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.LongVector; +import jdk.incubator.vector.VectorMask; +import jdk.incubator.vector.VectorOperators; +import jdk.test.lib.Asserts; + +public class TestLateInlineNullableReceiver { + static final VectorMask MASK = FloatVector.SPECIES_128.maskAll(true); + // Another (unused) mask to prevent dervirtualization of the 'trueCount' call + static final VectorMask OTHER_MASK = FloatVector.SPECIES_64.maskAll(true); + + static VectorMask lateInlined(Object value) { + return (VectorMask) MASK.getClass().cast(value); + } + + static int test(Object value) { + // XOR a vector and make sure it's live at below virtual call + IntVector vector = IntVector.fromArray(IntVector.SPECIES_128, new int[4], 0).lanewise(VectorOperators.XOR, 0); + + // After late inlining, 'value' is exact but still nullable. C2 will then + // attempt to strength reduce the 'trueCount' virtual call to a static call. + int result = lateInlined(value).trueCount(); + + return result + vector.lane(0); // Keep the vector live + } + + public static void main(String[] args) { + for (int i = 0; i < 200; i++) { + Asserts.assertEquals(test(MASK), 4); + } + } +} + From b18c13fbf7cbf01d4d929a043a3fca1c0ddf9d82 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 31 Aug 2026 06:11:52 +0000 Subject: [PATCH 147/223] 8390782: TestExpressions.java does not correctly handle NaNs in Float16 reduction result Reviewed-by: thartmann, chagedorn --- .../template_framework/examples/TestExpressions.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java index 8e87985e3d30..54eb01f8b3bf 100644 --- a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java +++ b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java @@ -48,6 +48,7 @@ import static compiler.lib.template_framework.Template.let; import compiler.lib.template_framework.library.Expression; import compiler.lib.template_framework.library.Operations; +import compiler.lib.template_framework.library.ShortCarriesFloat16Type; import compiler.lib.template_framework.library.TestFrameworkClass; public class TestExpressions { @@ -88,6 +89,12 @@ public static String generate(CompileFramework comp) { // precision results from some operators. We only compare the results if we know that the // result is deterministically the same. TemplateToken expressionToken = expression.asToken(expression.argumentTypes.stream().map(t -> t.con()).toList()); + // Float16Vector lane()/reduceLanes() return a short carrier; box to Float16 so + // Verify.checkEQ canonicalizes NaN. + boolean float16CarrierResult = expression.returnType instanceof ShortCarriesFloat16Type; + List returnStmt = float16CarrierResult + ? List.of("return Float16.shortBitsToFloat16(", expressionToken, ");\n") + : List.of("return ", expressionToken, ";\n"); return scope( let("returnType", expression.returnType), """ @@ -104,7 +111,7 @@ public static String generate(CompileFramework comp) { public static Object ${primitiveConTest}_compiled() { try { """, - "return ", expressionToken, ";\n", + returnStmt, expression.info.exceptions.stream().map(exception -> "} catch (" + exception + " e) { return e;\n" ).toList(), @@ -118,7 +125,7 @@ public static String generate(CompileFramework comp) { public static Object ${primitiveConTest}_reference() { try { """, - "return ", expressionToken, ";\n", + returnStmt, expression.info.exceptions.stream().map(exception -> "} catch (" + exception + " e) { return e;\n" ).toList(), From db3e0a5f600f1fd2eca2fb3cc96f0784652f332b Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 31 Aug 2026 06:58:00 +0000 Subject: [PATCH 148/223] 8389901: [windows] CCombinedSegTable::GetEUDCFileName from awt_Font.cpp seems to miss RegCloseKey calls Reviewed-by: prr, azvegint --- .../windows/native/libawt/windows/awt_Font.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp index fac9a0222097..b0bd6d891e28 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp @@ -1764,15 +1764,16 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) if (m_fEUDCSubKeyExist == FALSE) return; - // get filename of typeface-specific TureType EUDC font + // get filename of typeface-specific TrueType EUDC font LPSTR lpszSubKey = GetCodePageSubkey(); if (lpszSubKey == NULL) { m_fEUDCSubKeyExist = FALSE; return; // can not get codepage information } + DASSERT(strlen((LPCSTR)lpszSubKey) > 0); HKEY hRootKey = HKEY_CURRENT_USER; HKEY hKey; - LONG lRet = ::RegOpenKeyExA(hRootKey, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey); + LONG lRet = ::RegOpenKeyExA(hRootKey, lpszSubKey, 0, KEY_READ, &hKey); if (lRet != ERROR_SUCCESS) { m_fEUDCSubKeyExist = FALSE; return; // no EUDC font @@ -1802,10 +1803,13 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) BOOL fUseDefault = FALSE; if (lStatus != ERROR_SUCCESS){ // try System default EUDC font - if (m_fTTEUDCFileExist == FALSE) + if (m_fTTEUDCFileExist == FALSE) { + RegCloseKey(hKey); return; + } if (wcslen(m_szDefaultEUDCFile) > 0) { StringCchCopy(lpszFileName, cchFileName, m_szDefaultEUDCFile); + RegCloseKey(hKey); return; } char szDefault[] = "SystemDefaultEUDCFont"; @@ -1816,6 +1820,7 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) m_fTTEUDCFileExist = FALSE; // This font is associated with no EUDC font // and there is no system default EUDC font + RegCloseKey(hKey); return; } } @@ -1824,6 +1829,7 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) // This font is associated with no EUDC font // and the system default EUDC font is not TrueType m_fTTEUDCFileExist = FALSE; + RegCloseKey(hKey); return; } @@ -1832,6 +1838,7 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) (LPCSTR)szFileName, -1, lpszFileName, cchFileName) != 0); if (fUseDefault) StringCchCopy(m_szDefaultEUDCFile, _MAX_PATH, lpszFileName); + RegCloseKey(hKey); } void CCombinedSegTable::Create(LPCWSTR name) From abd93daad27a0467ddaa66840d1f8dff08626076 Mon Sep 17 00:00:00 2001 From: Lee Jiwon <107186291+dlwldnjs1009@users.noreply.github.com> Date: Mon, 31 Aug 2026 07:02:10 +0000 Subject: [PATCH 149/223] 8390064: Test sun/net/www/http/HttpClient/IsAvailable.java fails intermittently with AssertionFailedError: Connection over closed socket should not be available ==> expected: but was: Reviewed-by: vyazici --- .../net/www/http/HttpClient/IsAvailable.java | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java b/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java index 65752737c628..072a58022f7b 100644 --- a/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java +++ b/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java @@ -67,6 +67,7 @@ import org.junit.jupiter.api.Test; import sun.net.www.http.HttpClient; +import java.util.function.Function; import java.util.function.Predicate; import java.util.logging.ConsoleHandler; import java.util.logging.Level; @@ -117,6 +118,13 @@ void testClosedSocket() throws Exception { // Verify that closing the socket removes the availability LOGGER.info("Closing the socket..."); infra.clientSocket.close(); + // Closing the server socket may not immediately be observable by + // the client. Read from the client's _internal_ socket to ensure + // that EOF, which is necessary for the `HttpClient::available` + // verification, has arrived. + assertEquals( + -1, infra.readFromHttpClientSocket(), + "Expected EOF after closing the server socket"); LOGGER.info("Checking the connection (#2)..."); assertFalse(infra.available(), "Connection over closed socket should not be available"); assertEquals(readTimeout, infra.httpClient.getReadTimeout(), "Read-timeout should be restored"); @@ -142,10 +150,13 @@ void testSocketWithUnconsumedData() throws Exception { clientSocketOutputStream.write("unexpected data".getBytes(US_ASCII)); } - // Writing to the socket on the server side may not make the data - // immediately visible to the client side. Make sure we wait long - // enough for the data to get delivered. - Thread.sleep(adjustTimeout(500)); + // Writing to the server socket may not immediately be observable + // by the client. Read from the client's _internal_ socket to ensure + // that the data, which is necessary for the `HttpClient::available` + // verification, has arrived. + assertTrue( + infra.readFromHttpClientSocket() >= 0, + "Unexpected data should have arrived to the client socket"); // Verify that the presence of stale data on the socket removes the availability LOGGER.info("Checking the connection (#2)..."); @@ -161,6 +172,8 @@ private static final class Infra implements Closeable { private static final Predicate AVAILABLE_ACCESSOR = findAvailableAccessor(); + private static final Function SERVER_SOCKET_ACCESSOR = findServerSocketAccessor(); + private static Predicate findAvailableAccessor() { final MethodHandle availableMH; try { @@ -179,6 +192,24 @@ private static Predicate findAvailableAccessor() { }; } + private static Function findServerSocketAccessor() { + final MethodHandle serverSocketMH; + try { + serverSocketMH = MethodHandles + .privateLookupIn(HttpClient.class, MethodHandles.lookup()) + .findGetter(HttpClient.class, "serverSocket", Socket.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + return httpClient -> { + try { + return (Socket) serverSocketMH.invoke(httpClient); + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; + } + private final ServerSocket serverSocket; private final HttpClient httpClient; @@ -210,6 +241,17 @@ private boolean available() { return AVAILABLE_ACCESSOR.test(httpClient); } + private int readFromHttpClientSocket() throws IOException { + Socket socket = SERVER_SOCKET_ACCESSOR.apply(httpClient); + int timeout = socket.getSoTimeout(); + try { + socket.setSoTimeout((int) adjustTimeout(5000)); + return socket.getInputStream().read(); + } finally { + socket.setSoTimeout(timeout); + } + } + @Override public void close() { closeQuietly("client socket", clientSocket); From 7cae34c2902a2731408c53b09e30b9d9b4b71276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 31 Aug 2026 08:10:35 +0000 Subject: [PATCH 150/223] 8338094: C1: assert(result->covers(op_id, mode)) failed: op_id not covered by interval Co-authored-by: Daniel Skantz Reviewed-by: dlong, thartmann --- src/hotspot/share/c1/c1_LinearScan.cpp | 53 +++++++++++- .../TestExceptionBranchWithLiveRangeHole.java | 83 +++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/regalloc/TestExceptionBranchWithLiveRangeHole.java diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index 70dbad6d91ba..3cb30eab55db 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -744,7 +744,9 @@ void LinearScan::compute_global_live_sets() { // Perform a backward dataflow analysis to compute live_out and live_in for each block. // The loop is executed until a fixpoint is reached (no changes in an iteration) // Exception handlers must be processed because not all live values are - // present in the state array, e.g. because of global value numbering + // present in the state array, e.g. because of global value numbering. + // Exception handler live_in information is also used by build_intervals() to + // account for local liveness holes in exception-throwing blocks. do { change_occurred = false; @@ -1363,6 +1365,55 @@ void LinearScan::build_intervals() { add_use(opr, block_from, op_id, use_kind_of_input_operand(op, opr)); } + // If the visited operation 'op' may branch into an exception handler + // block 'handler', add all live-in registers of 'handler' as virtual uses + // of 'op'. This ensures that all such registers are live into 'op', which + // might otherwise not happen if 'op' is scheduled within a hole of their + // corresponding intervals, as in the following + // post-compute_global_live_sets() scenario: + // + // R + // | block: + // | live-in: {.., R, ..} + // | .. + // - kill R + // .. + // op: branch [BE] .. // may branch into 'handler' + // .. + // - def R + // | .. + // | branch into 'block' + // | live-out: {.., R, ..} + // | + // | handler: + // | live-in: {.., R, ..} + // | .. + // + // Normally, the debug information generation logic below will add + // registers such as R in the above scenario as uses of 'op', but this + // might not happen if the corresponding virtual register used within + // 'handler' is replaced by another one in an earlier optimization pass. + // An example of such a replacement is GraphBuilder::shift_op(). + if (compilation()->has_exception_handlers() && op_id != -1 && has_info(op_id)) { + XHandlers* xhandlers = visitor.all_xhandler(); + for (int k = 0; k < xhandlers->length(); k++) { + BlockBegin* handler = xhandlers->handler_at(k)->entry_block(); + auto add_virtual_use_to_op = [&](BitMap::idx_t index) { + int reg = static_cast(index); + // The T_ILLEGAL type is used by add_use() as a sentinel value + // indicating the type is unknown (rather than illegal) so that the + // type of the interval corresponding to reg is not updated. The use + // is extended beyond 'op' (to = op_id + 1) so that liveness is + // preserved across possible registers killed by 'op' (e.g. + // caller-saved registers if 'op' is a call). + TRACE_LINEAR_SCAN(2, tty->print_cr(" use [R%d] from %d to %d (%d)", + reg, block_from, op_id + 1, noUse)); + add_use(reg, block_from, op_id + 1, noUse, T_ILLEGAL); + }; + handler->live_in().iterate(add_virtual_use_to_op); + } + } + // Add uses of live locals from interpreter's point of view for proper // debug information generation // Treat these operands as temp values (if the life range is extended diff --git a/test/hotspot/jtreg/compiler/regalloc/TestExceptionBranchWithLiveRangeHole.java b/test/hotspot/jtreg/compiler/regalloc/TestExceptionBranchWithLiveRangeHole.java new file mode 100644 index 000000000000..1b4d5870c411 --- /dev/null +++ b/test/hotspot/jtreg/compiler/regalloc/TestExceptionBranchWithLiveRangeHole.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.regalloc; + +/** + * @test + * @bug 8338094 + * @summary Test C1's computation of local live ranges across exception jumps. + * @run main/othervm -Xbatch + * -XX:TieredStopAtLevel=1 + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + * @run main ${test.main.class} + */ + +class TestExceptionBranchWithLiveRangeHole { + + // Test that liveness information is computed correctly by C1 for intervals + // that are live at an exception throwing operation solely because they are + // used within the exception handler block. + static void testThrowIOBE() { + int i = 0; + int[] array = new int[1]; + try { + for (;;) { + i = i << 32; + // The pre-shift value of i should be live here, because it is + // used below in the exception handler code, after the + // canonicalization (i << 32) >>> 32 => i is applied. + array[1] = 0; + } + } catch (ArrayIndexOutOfBoundsException e) { + array[i >>> 32] = 42; + } + } + + // Variant of the above test using a different type of exception. + // Illustrates the need of extending the live range of i beyond the + // o.toString() call to model the interference of i with the killed + // caller-saved registers. + static void testThrowNPE(Object o) { + int i = 0; + int[] array = new int[1]; + try { + for (;;) { + i = i << 32; + o.toString(); + } + } catch (NullPointerException e) { + array[i >>> 32] = 42; + } + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + testThrowIOBE(); + } + for (int i = 0; i < 10_000; i++) { + testThrowNPE(null); + } + } +} From d81a9042fa4c270b95ac05338f9970c4014aa826 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 31 Aug 2026 08:57:39 +0000 Subject: [PATCH 151/223] 8387971: Minor comment typos "successfull" Reviewed-by: dholmes --- src/hotspot/os/linux/cgroupSubsystem_linux.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 1c183a9bbab5..18c1c1eb26f7 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -670,7 +670,7 @@ bool CgroupSubsystem::active_processor_count(int (*cpu_bound_func)(), double& va * * return: * false if retrieving the value failed - * true if retrieving the value was successfull and the value was + * true if retrieving the value was successful and the value was * set in the 'value' reference. */ bool CgroupSubsystem::memory_limit_in_bytes(physical_memory_size_type upper_bound, diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 0b79c7a4285a..9c77c5e30abf 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -2135,7 +2135,7 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz // goal without. In that case, we optimize probing by sorting the attach // points: We attempt outermost points first, then work ourselves up to // the middle. That reduces address space fragmentation. We also alternate - // hemispheres, which increases the chance of successfull mappings if the + // hemispheres, which increases the chance of successful mappings if the // previous mapping had been blocked by large maps. hemi_split(points, num_attempts); } From 55c159fd88e89d34585c19d4c94fd60a1b211e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 31 Aug 2026 09:07:58 +0000 Subject: [PATCH 152/223] 8387276: Replace LinkedList with GrowableArray in shared trampolines Reviewed-by: coleenp, cnorrbin --- src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp | 16 ++++++++++------ src/hotspot/share/asm/codeBuffer.hpp | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp index 97d9f7afdfb4..9c8c7393354d 100644 --- a/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -37,7 +38,7 @@ void CodeBuffer::share_trampoline_for(address dest, int caller_offset) { if (created) { _shared_trampoline_requests->maybe_grow(); } - offsets->add(caller_offset); + offsets->push(caller_offset); _finalize_stubs = true; } @@ -50,16 +51,19 @@ static bool emit_shared_trampolines(CodeBuffer* cb, CodeBuffer::SharedTrampoline MacroAssembler masm(cb); - auto emit = [&](address dest, const CodeBuffer::Offsets &offsets) { + auto emit = [&](address dest, const CodeBuffer::Offsets& offsets) { assert(cb->stubs()->remaining() >= MacroAssembler::max_trampoline_stub_size(), "pre-allocated trampolines"); - LinkedListIterator it(offsets.head()); - int offset = *it.next(); + assert(offsets.length() > 0, "must be"); + // We go backwards + const int offset_end = offsets.length() - 1; + int offset = offsets.at(offset_end); address stub = __ emit_trampoline_stub(offset, dest); assert(stub, "pre-allocated trampolines"); address reloc_pc = cb->stubs()->end() - NativeCallTrampolineStub::instruction_size; - while (!it.is_empty()) { - offset = *it.next(); + // Skip the first one + for (int i = offset_end - 1; i >= 0; i--) { + offset = offsets.at(i); address caller_pc = cb->insts()->start() + offset; cb->stubs()->relocate(reloc_pc, trampoline_stub_Relocation::spec(caller_pc)); } diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index d56ab27f0253..549b2cb20639 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -28,11 +28,11 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" #include "compiler/compiler_globals.hpp" +#include "nmt/memTag.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" -#include "utilities/linkedlist.hpp" #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" @@ -546,7 +546,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { SECT_LIMIT, SECT_NONE = -1 }; - typedef LinkedListImpl Offsets; + typedef GrowableArrayCHeap Offsets; typedef ResizeableHashTable SharedTrampolineRequests; private: From c2e533648c31418ddc1d652d786bfe033a3c7ef4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Aug 2026 12:59:39 +0000 Subject: [PATCH 153/223] 8371868: Use desktop-file-validate command to validate desktop entry files created by jpackage Reviewed-by: almatvee --- .../jdk/jpackage/internal/DesktopEntry.java | 80 +++++++ .../internal/DesktopEntryFileValidator.java | 74 ++++++ .../jpackage/internal/DesktopIntegration.java | 50 ++++- .../internal/LinuxBundlingEnvironment.java | 3 +- .../jpackage/internal/LinuxFromOptions.java | 7 +- .../internal/LinuxPackageBuilder.java | 58 ++++- .../jdk/jpackage/internal/LinuxPackager.java | 74 +++++- .../internal/LinuxSystemEnvironment.java | 13 +- .../resources/LinuxResources.properties | 5 + .../jpackage/internal/BuildEnvBuilder.java | 9 - .../jdk/jpackage/test/JPackageCommand.java | 16 ++ .../test/JPackageOutputValidator.java | 2 +- .../jdk/jpackage/test/LinuxHelper.java | 107 ++++++++- .../DesktopEntryFileValidatorTest.java | 83 +++++++ .../jpackage/internal/DesktopEntryTest.java | 108 +++++++++ .../internal/LinuxPackageBuilderTest.java | 182 +++++++++++++++ .../jdk/tools/jpackage/junit/linux/junit.java | 26 +++ .../cli/OptionsValidationFailTest.excludes | 26 ++- .../jpackage/linux/ShortcutHintTest.java | 8 +- test/jdk/tools/jpackage/share/BasicTest.java | 2 + test/jdk/tools/jpackage/share/ErrorTest.java | 212 +++++++++++++----- .../jpackage/share/FileAssociationsTest.java | 4 + test/jdk/tools/jpackage/share/IconTest.java | 2 +- .../tools/jpackage/share/InstallDirTest.java | 2 + .../tools/jpackage/share/MainClassTest.java | 7 +- .../tools/jpackage/share/ModularAppTest.java | 2 + .../tools/jpackage/share/OutputErrorTest.java | 2 + 27 files changed, 1066 insertions(+), 98 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntry.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntryFileValidator.java create mode 100644 test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryFileValidatorTest.java create mode 100644 test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryTest.java create mode 100644 test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntry.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntry.java new file mode 100644 index 000000000000..8340765dd7c8 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntry.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Objects; +import jdk.jpackage.internal.util.Enquoter; + +/** + * A subset of desktop entries set by jpackage. + *

      + * See Recognized + * desktop entry keys for the full set. + */ +enum DesktopEntry { + + MIME_TYPE("MimeType"), + NAME("Name"), + COMMENT("Comment"), + EXEC("Exec"), + PATH("Path"), + ICON("Icon"), + TERMINAL("Terminal"), + TYPE("Type"), + CATEGORIES("Categories"), + ; + + DesktopEntry(String desktopEntryKey) { + this.desktopEntryKey = Objects.requireNonNull(desktopEntryKey); + } + + String formatDesktopFileEntryValue(String v) { + Objects.requireNonNull(v); + return switch (this) { + case MIME_TYPE, CATEGORIES -> ensureEndsWithSemicolon(v); + case EXEC -> Enquoter.forPropertyValues().applyTo(v); + default -> v; + }; + } + + String formatDesktopFileEntry(String v) { + return desktopEntryKey + "=" + formatDesktopFileEntryValue(v); + } + + String entryKey() { + return desktopEntryKey; + } + + private static String ensureEndsWithSemicolon(String str) { + if (!str.endsWith(";")) { + return str + ';'; + } else { + return str; + } + } + + private final String desktopEntryKey; +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntryFileValidator.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntryFileValidator.java new file mode 100644 index 000000000000..e5c6c082141a --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopEntryFileValidator.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicBoolean; +import jdk.jpackage.internal.util.CommandOutputControl.Result; + + +@FunctionalInterface +interface DesktopEntryFileValidator { + + Result validate(Path desktopEntryFile); + + /** + * Creates desktop entry file validator that will run the + * {@code desktop-file-validate} command in every invocation of the + * {@link #validate(Path)} until the first failure to execute the command. In + * such an event, the validator will return a {@link Result} without the exit + * code and will keep returning such a value in subsequent invocations without + * calling the command. + * + * @return the desktop entry file validator + */ + static DesktopEntryFileValidator createDefault() { + return new DesktopEntryFileValidator() { + + @Override + public Result validate(Path desktopEntryFile) { + if (stop.get()) { + return EMPTY_RESULT; + } else { + try { + return Executor.of("desktop-file-validate".toString(), desktopEntryFile.toString()).execute(); + } catch (IOException ex) { + // The command probably isn't available. + Log.trace(ex); + // Return result without the exit code. + stop.set(true); + return EMPTY_RESULT; + } + } + } + + private final AtomicBoolean stop = new AtomicBoolean(); + + private static final Result EMPTY_RESULT = Result.build().create(); + }; + } + +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index fad901699c35..f2499897ad96 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -34,12 +34,16 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; @@ -50,7 +54,6 @@ import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.util.CompositeProxy; -import jdk.jpackage.internal.util.Enquoter; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; @@ -138,6 +141,21 @@ static ShellCustomAction create(BuildEnv env, Package pkg) { (LinuxLauncher) pkg.app().mainLauncher().orElseThrow()); } + SortedMap cookedDesktopEntryFiles() { + return unfold().flatMap(v -> { + return v.desktopFile.stream().map(InstallableFile::srcPath).map(path -> { + return Map.entry(v.launcher, path); + }); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> { + throw new IllegalStateException(); + }, () -> { + // The main launcher first; additional launchers follow, sorted by name. + return new TreeMap<>(Comparator.comparingInt(launcher -> { + return launcher == pkg.app().mainLauncher().orElseThrow() ? 0 : 1; + }).thenComparing(LinuxLauncher::name)); + })); + } + @Override List requiredPackages() { return Stream.of(List.of(this), nestedIntegrations).flatMap( @@ -220,12 +238,12 @@ private Map createDataForDesktopFile() { var installedLayout = pkg.asInstalledPackageApplicationLayout().orElseThrow(); Map data = new HashMap<>(); - data.put("APPLICATION_NAME", launcher.name()); - data.put("APPLICATION_DESCRIPTION", launcher.description()); + data.put("APPLICATION_NAME", DesktopEntry.NAME.formatDesktopFileEntryValue(launcher.name())); + data.put("APPLICATION_DESCRIPTION", DesktopEntry.COMMENT.formatDesktopFileEntryValue(launcher.description())); data.put("APPLICATION_ICON", iconFile.map( - f -> f.installPath().toString()).orElse(null)); - data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName()); - data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( + f -> DesktopEntry.ICON.formatDesktopFileEntryValue(f.installPath().toString())).orElse(null)); + data.put("DEPLOY_BUNDLE_CATEGORY", DesktopEntry.CATEGORIES.formatDesktopFileEntryValue(pkg.menuGroupName())); + data.put("APPLICATION_LAUNCHER", DesktopEntry.EXEC.formatDesktopFileEntryValue( installedLayout.launchersDirectory().resolve(launcher.executableNameWithSuffix()).toString())); data.put("STARTUP_DIRECTORY", launcher.shortcut() .flatMap(LauncherShortcut::startupDirectory) @@ -241,13 +259,15 @@ private Map createDataForDesktopFile() { throw new AssertionError(); } } - }).map(str -> { - return "Path=" + str; - }).orElse(null)); + }).map(Path::toString).map(DesktopEntry.PATH::formatDesktopFileEntry).orElse(null)); return data; } + private Stream unfold() { + return Stream.concat(Stream.of(this), nestedIntegrations.stream().flatMap(DesktopIntegration::unfold)); + } + /** * Shell commands to integrate something with desktop. */ @@ -413,7 +433,17 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) private void saveDesktopFile(Map data) throws IOException { List mimeTypes = getMimeTypeNamesFromFileAssociations(); - data.put("DESKTOP_MIMES", "MimeType=" + String.join(";", mimeTypes)); + // Don't write an empty "MimeType" desktop entry. + // To pass validation with the older desktop-file-validate command, + // the value must end with a semicolon (;). + // If the list is empty, the value of the entry becomes a semicolon + // and barely passes validation with a newer desktop-file-validate command; + // it emits a non-fatal error: + // + // (error: (will be fatal in the future): value ";" for key "MimeType" in group "Desktop Entry" contains value "" which is an invalid MIME type: "" does not contain a subtype). + // + data.put("DESKTOP_MIMES", mimeTypes.isEmpty() ? null + : DesktopEntry.MIME_TYPE.formatDesktopFileEntry(String.join(";", mimeTypes))); // prepare desktop shortcut desktopFileResource diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java index baf5e0bbbf09..32edae461195 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java @@ -136,7 +136,8 @@ private static Result adjustPackageArch(LinuxSystemEnvir }); } else { return LinuxPackageArch.create(type).map(arch -> { - return new LinuxSystemEnvironment.Stub(sysEnv.soLookupAvailable(), sysEnv.nativePackageType(), arch); + return new LinuxSystemEnvironment.Stub( + sysEnv.soLookupAvailable(), sysEnv.nativePackageType(), arch, sysEnv.desktopEntryFileValidator()); }); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java index 7fd9fd80d7e6..2097d35c3382 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java @@ -36,6 +36,7 @@ import static jdk.jpackage.internal.cli.StandardOption.LINUX_RELEASE; import static jdk.jpackage.internal.cli.StandardOption.LINUX_RPM_LICENSE_TYPE; import static jdk.jpackage.internal.cli.StandardOption.LINUX_SHORTCUT_HINT; +import static jdk.jpackage.internal.cli.StandardOption.TEMP_ROOT; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; @@ -126,7 +127,11 @@ private static LinuxPackageBuilder createLinuxPackageBuilder(Options options, Li LINUX_PACKAGE_DEPENDENCIES.ifPresentIn(options, pkgBuilder::additionalDependencies); LINUX_APP_CATEGORY.ifPresentIn(options, pkgBuilder::category); - LINUX_MENU_GROUP.ifPresentIn(options, pkgBuilder::menuGroupName); + LINUX_MENU_GROUP.ifPresentIn(options, v -> { + pkgBuilder.menuGroupName(v) + .probeMenuGroupNameFile(TEMP_ROOT.getFrom(options).resolve("desktop-file-validate/probe.desktop")); + pkgBuilder.desktopEntryFileValidator(sysEnv.desktopEntryFileValidator()); + }); LINUX_RELEASE.ifPresentIn(options, pkgBuilder::release); LINUX_PACKAGE_NAME.ifPresentIn(options, pkgBuilder::literalName); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 1ac3e281ab68..60cd81824463 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -26,12 +26,17 @@ import static jdk.jpackage.internal.I18N.buildConfigException; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.LinuxPackageMixin; @@ -71,6 +76,12 @@ LinuxPackage create() { final var app = ApplicationBuilder.overrideAppImageLayout(pkgBuilder.app(), relativeInstalledLayout); + menuGroupName().filter(_ -> { + return desktopEntryFileValidator != null && probeMenuGroupNameFile != null; + }).ifPresent(v -> { + validateMenuGroupName(desktopEntryFileValidator, probeMenuGroupNameFile, v); + }); + return create(pkgBuilder .app(LinuxApplication.create(app)) .installedPackageLayout(relativeInstalledLayout.resolveAt(Path.of("/")).resetRootDirectory()) @@ -79,7 +90,7 @@ LinuxPackage create() { private LinuxPackage create(Package pkg) { return LinuxPackage.create(pkg, new LinuxPackageMixin.Stub( - Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), + menuGroupName().orElseGet(DEFAULTS::menuGroupName), category(), Optional.ofNullable(additionalDependencies), release(), @@ -96,6 +107,10 @@ LinuxPackageBuilder menuGroupName(String v) { return this; } + Optional menuGroupName() { + return Optional.ofNullable(menuGroupName); + } + LinuxPackageBuilder category(String v) { category = v; return this; @@ -124,6 +139,16 @@ LinuxPackageBuilder arch(LinuxPackageArch v) { return this; } + LinuxPackageBuilder probeMenuGroupNameFile(Path v) { + probeMenuGroupNameFile = v; + return this; + } + + LinuxPackageBuilder desktopEntryFileValidator(DesktopEntryFileValidator v) { + desktopEntryFileValidator = v; + return this; + } + private static LinuxApplicationLayout usrTreePackageLayout(Path prefix, String packageName) { final var lib = prefix.resolve(Path.of("lib", packageName)); return LinuxApplicationLayout.create( @@ -182,6 +207,35 @@ private static void validatePackageName(String packageName, StandardPackageType } } + private static void validateMenuGroupName(DesktopEntryFileValidator desktopEntryFileValidator, Path probeFile, String menuGroupName) { + Objects.requireNonNull(desktopEntryFileValidator); + Objects.requireNonNull(probeFile); + Objects.requireNonNull(menuGroupName); + + try { + Files.createDirectories(probeFile.getParent()); + Files.write(probeFile, List.of( + "[Desktop Entry]", + DesktopEntry.NAME.formatDesktopFileEntry("acme"), + DesktopEntry.EXEC.formatDesktopFileEntry("foo"), + DesktopEntry.TYPE.formatDesktopFileEntry("Application"), + DesktopEntry.CATEGORIES.formatDesktopFileEntry(menuGroupName))); + } catch (IOException ex) { + // This is fatal if we can't create a probe file. + throw new UncheckedIOException(ex); + } + + var result = desktopEntryFileValidator.validate(probeFile); + result.exitCode().ifPresent(exitCode -> { + if (exitCode != 0) { + // Validation failed as the command returned an unexpected exit code. + throw new ConfigException( + I18N.format("error.parameter-invalid-value", menuGroupName, "--linux-menu-group"), + I18N.format("error.invalid-desktop-category.advice")); + } + }); + } + private record Defaults(String menuGroupName) { } @@ -190,6 +244,8 @@ private record Defaults(String menuGroupName) { private String category; private String additionalDependencies; private String release; + private Path probeMenuGroupNameFile; + private DesktopEntryFileValidator desktopEntryFileValidator; private LinuxPackageArch arch; private final PackageBuilder pkgBuilder; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java index 63f35fd6a659..810fd0ca82f1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -28,11 +28,14 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.SortedMap; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; @@ -40,24 +43,36 @@ import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.LinuxPackage; abstract class LinuxPackager implements Consumer { LinuxPackager(BuildEnv env, T pkg, Path outputDir, LinuxSystemEnvironment sysEnv) { this.env = Objects.requireNonNull(env); + this.sysEnv = Objects.requireNonNull(sysEnv); this.pkg = Objects.requireNonNull(pkg); this.outputDir = Objects.requireNonNull(outputDir); this.withRequiredPackagesLookup = isWithRequiredPackagesSearch(sysEnv, pkg); + var desktopIntegration = DesktopIntegration.create(env, pkg); + + if (desktopIntegration instanceof DesktopIntegration di) { + cookedDesktopEntryFiles = di.cookedDesktopEntryFiles(); + } else { + cookedDesktopEntryFiles = Collections.emptySortedMap(); + } + customActions = List.of( - DesktopIntegration.create(env, pkg), + desktopIntegration, LinuxLaunchersAsServices.create(env, pkg)); } enum LinuxPackageTaskID implements TaskID { INIT_REQUIRED_PACKAGES, - VERIFY_PACKAGE + VERIFY_PACKAGE, + VALIDATE_DESKTOP_ENTRY_FILES, } @Override @@ -66,6 +81,11 @@ public void accept(PackagingPipeline.Builder pipelineBuilder) { .task(PackageTaskID.CREATE_CONFIG_FILES) .action(this::buildConfigFiles) .add() + .task(LinuxPackageTaskID.VALIDATE_DESKTOP_ENTRY_FILES) + .addDependency(PackageTaskID.CREATE_CONFIG_FILES) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::validateDesktopEntryFiles) + .add() .task(LinuxPackageTaskID.INIT_REQUIRED_PACKAGES) .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) .addDependent(PackageTaskID.CREATE_CONFIG_FILES) @@ -79,6 +99,10 @@ public void accept(PackagingPipeline.Builder pipelineBuilder) { .task(PackageTaskID.CREATE_PACKAGE_FILE) .action(this::buildPackage) .add(); + + if (cookedDesktopEntryFiles.isEmpty()) { + pipelineBuilder.task(LinuxPackageTaskID.VALIDATE_DESKTOP_ENTRY_FILES).noaction(); + } } protected final Path outputPackageFile() { @@ -159,6 +183,48 @@ private List findRequiredPackages() throws IOException { return lookup.execute(env.appImageDir()); } + private void validateDesktopEntryFiles() { + + List errorMessages = new ArrayList<>(); + + for (var e : cookedDesktopEntryFiles.entrySet()) { + var result = sysEnv.desktopEntryFileValidator().validate(e.getValue()); + result.exitCode().ifPresent(exitCode -> { + if (exitCode != 0) { + if (e.getKey() == pkg.app().mainLauncher().orElseThrow()) { + errorMessages.add(I18N.format( + "error.invalid-desktop-entry-file.main-launcher", e.getValue())); + } else { + errorMessages.add(I18N.format( + "error.invalid-desktop-entry-file.add-launcher", e.getValue(), e.getKey().name())); + } + } + }); + } + + if (errorMessages.isEmpty()) { + return; + } + + var advice = I18N.format("error.invalid-desktop-entry-file.advice"); + + // + // Order exceptions such that in the error output they appear + // in the same order as error messages in the `errorMessages` list. + // Add a single advice entry to the error output. + // + + throw Stream.concat( + Stream.of(errorMessages.getLast()).map(message -> { + return new ConfigException(message, advice); + }), + errorMessages.stream().limit(errorMessages.size() - 1).map(JPackageException::new) + ).reduce((a, b) -> { + a.addSuppressed(b); + return a; + }).orElseThrow(); + } + private void verifyOutputPackage() { final List errors; try { @@ -178,9 +244,11 @@ private void verifyOutputPackage() { } protected final BuildEnv env; + private final LinuxSystemEnvironment sysEnv; protected final T pkg; protected final Path outputDir; private final boolean withRequiredPackagesLookup; private List requiredPackages; - private final List customActions; + private final Collection customActions; + private final SortedMap cookedDesktopEntryFiles; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java index d58d3e8b40da..7813cc959cd2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java @@ -40,6 +40,7 @@ interface LinuxSystemEnvironment extends SystemEnvironment { boolean soLookupAvailable(); PackageType nativePackageType(); LinuxPackageArch packageArch(); + DesktopEntryFileValidator desktopEntryFileValidator(); static Result create() { return detectNativePackageType().map(LinuxSystemEnvironment::create).orElseGet(() -> { @@ -64,7 +65,11 @@ static Optional detectNativePackageType() { static Result create(StandardPackageType nativePackageType) { return LinuxPackageArch.create(nativePackageType).map(arch -> { - return new Stub(LibProvidersLookup.supported(), nativePackageType, arch); + return new Stub( + LibProvidersLookup.supported(), + nativePackageType, + arch, + DesktopEntryFileValidator.createDefault()); }); } @@ -87,7 +92,11 @@ static Result mixin(Class type, } } - record Stub(boolean soLookupAvailable, PackageType nativePackageType, LinuxPackageArch packageArch) implements LinuxSystemEnvironment { + record Stub( + boolean soLookupAvailable, + PackageType nativePackageType, + LinuxPackageArch packageArch, + DesktopEntryFileValidator desktopEntryFileValidator) implements LinuxSystemEnvironment { } static final class Internal { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index dcdc96323ef3..be6b61147798 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -48,6 +48,11 @@ error.deb-invalid-value-for-package-name.advice=Set the "--linux-package-name" o error.rpm-invalid-value-for-package-name=Invalid value "{0}" for the package name. error.rpm-invalid-value-for-package-name.advice=Set the "--linux-package-name" option to a valid RPM package name. Note that the package names must consist only of letters (a-z, A-Z), digits (0-9), plus (+) and minus (-) signs, periods (.) and underscores (_). They must be at least one character long and must start with a letter. +error.invalid-desktop-category.advice=Specify a value that is valid for the "Categories" key in a desktop entry file and passes validation by the desktop-file-validate command +error.invalid-desktop-entry-file.main-launcher=Invalid main desktop entry file "{0}" +error.invalid-desktop-entry-file.add-launcher=Invalid desktop entry file "{0}" for the [{1}] additional launcher +error.invalid-desktop-entry-file.advice=Use a desktop entry file template that passes validation by the desktop-file-validate command + error.rpm-arch-not-detected="Failed to detect RPM arch" message.icon-not-png=The specified icon "{0}" is not a PNG file and will not be used. The default icon will be used in it's place. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 77354cb2c53f..aa0e0f357eb2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.cli.StandardValidator.IS_DIRECTORY_EMPTY_OR_NON_EXISTENT_PREDICATE; - import java.nio.file.Path; import java.util.Objects; import java.util.Optional; @@ -41,13 +39,6 @@ final class BuildEnvBuilder { } BuildEnv create() { - // The directory should be validated earlier with a proper error message. - // Here is only a sanity check. - if (!IS_DIRECTORY_EMPTY_OR_NON_EXISTENT_PREDICATE.test(root)) { - throw new UnsupportedOperationException( - String.format("Root work directory [%s] should be empty or non existent", root)); - } - return BuildEnv.create( root, Optional.ofNullable(resourceDir), diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index eda354079bf4..25b1c3a9784f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1012,6 +1012,14 @@ public JPackageCommand setEnabledMessageCategories(MessageCategory... categories return setEnabledMessageCategories(Set.of(categories)); } + public JPackageCommand enableMessageCategories(Set categories) { + return setEnabledMessageCategories(SetBuilder.build(logConfig.add()).add(categories).emptyAllowed(true).create()); + } + + public JPackageCommand enableMessageCategories(MessageCategory... categories) { + return enableMessageCategories(Set.of(categories)); + } + public JPackageCommand setDisabledMessageCategories(Set categories) { verifyMutable(); logConfig = new LogConfig( @@ -1024,6 +1032,14 @@ public JPackageCommand setDisabledMessageCategories(MessageCategory... categorie return setDisabledMessageCategories(Set.of(categories)); } + public JPackageCommand disableMessageCategories(Set categories) { + return setDisabledMessageCategories(SetBuilder.build(logConfig.remove()).add(categories).emptyAllowed(true).create()); + } + + public JPackageCommand disableMessageCategories(MessageCategory... categories) { + return disableMessageCategories(Set.of(categories)); + } + public static Set messageCategoriesConsoleAll() { return Stream.of(MessageCategory.values()).filter(MessageCategory::isConsole).collect(toSet()); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java index 8817ca0b7300..72a02362598a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java @@ -130,7 +130,7 @@ public JPackageOutputValidator matchTimestamps() { *

      * If the stream contains lines without timestampts, the validation will fail. *

      - * Use {@link #matchTimestamps()) to filter out lines without timestamps and + * Use {@link #matchTimestamps()} to filter out lines without timestamps and * prevent validation failure. * * @return this diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index dc8d79ca8411..b4d421c52e50 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -24,6 +24,7 @@ import static java.util.Collections.unmodifiableSortedSet; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; import static jdk.jpackage.internal.util.MemoizingSupplier.runOnce; @@ -54,6 +55,7 @@ import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.Result; import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.LauncherShortcut.InvokeShortcutSpec; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -93,6 +95,10 @@ public static Path getDesktopFile(JPackageCommand cmd, String launcherName) { desktopFileName); } + public static boolean isDesktopFileValidateCommandAvailable() { + return DesktopFileValidateAvailable.VALUE; + } + static Path getServiceUnitFilePath(JPackageCommand cmd, String launcherName) { cmd.verifyIsOfType(PackageType.LINUX); return cmd.pathToUnpackedPackageFile( @@ -434,6 +440,11 @@ static void addBundleDesktopIntegrationVerifier(PackageTest test, boolean integr "Check there are no .desktop files in the package"); } }); + + test.addInitializer(cmd -> { + cmd.enableMessageCategories(MessageCategory.TOOLS); + verifyDesktopFileValidateInvocationsInOutput(cmd, integrated); + }); } static void verifyDesktopIntegrationFiles(JPackageCommand cmd, boolean installed) { @@ -568,7 +579,8 @@ private static void verifyDesktopFile(JPackageCommand cmd, Optional { + var validatedDesktopEntryFiles = result.stdout().stream() + .filter(JPackageCommand::withTimestamp) + .map(JPackageCommand::stripTimestamp) + .mapMulti((str, sink) -> { + if (str.startsWith(startsWith)) { + sink.accept(Path.of(unquoteIfNeeded(str.substring(startsWith.length())))); + } + }).collect(toCollection(ArrayList::new)); + + if (cmd.hasArgument("--linux-menu-group")) { + TKit.assertTrue(!validatedDesktopEntryFiles.isEmpty(), + "Check that there are traces of desktop-file-validate executions in the output"); + TKit.assertEquals("probe.desktop", validatedDesktopEntryFiles.getFirst().getFileName().toString(), + "Check the name of the file used in the first desktop-file-validate execution"); + validatedDesktopEntryFiles.remove(0); + } + + if (!integrated) { + TKit.assertEquals(List.of(), validatedDesktopEntryFiles, + "Check there are no unexpected traces of desktop-file-validate executions in the output"); + return; + } + + if (!isDesktopFileValidateCommandAvailable()) { + int expectedCount; + if (cmd.hasArgument("--linux-menu-group")) { + expectedCount = 0; + } else { + expectedCount = 1; + } + + TKit.assertEquals(expectedCount, validatedDesktopEntryFiles.size(), + String.format( + "Check that the remaining number of traces of desktop-file-validate executions %s in the output is as expected", + validatedDesktopEntryFiles)); + return; + } + + final List expectedValidatedDesktopEntryFileNames; + if (integrated) { + getDesktopFile(cmd, null); + var launcherDesktopEntryFilenames = cmd.launcherNames(true).stream().map(launcherName -> { + return getLauncherDesktopFileName(cmd, launcherName); + }).toList(); + expectedValidatedDesktopEntryFileNames = getDesktopFiles(cmd).stream() + .map(Path::getFileName) + .filter(launcherDesktopEntryFilenames::contains) + .toList(); + } else { + expectedValidatedDesktopEntryFileNames = List.of(); + } + + var missing = expectedValidatedDesktopEntryFileNames.stream().filter(fileName -> { + return validatedDesktopEntryFiles.stream().map(Path::getFileName).filter(Predicate.isEqual(fileName)).findAny().isEmpty(); + }).sorted().toList(); + + var unexpected = validatedDesktopEntryFiles.stream().filter(path -> { + return !expectedValidatedDesktopEntryFileNames.contains(path.getFileName()); + }).sorted().toList(); + + TKit.assertEquals(List.of(), missing, "Check there are no missing traces of desktop-file-validate executions in the output"); + TKit.assertEquals(List.of(), unexpected, "Check there are no unexpected traces of desktop-file-validate executions in the output"); + }); + } + + private static String unquoteIfNeeded(String str) { + if (str.length() < 2) { + return str; + } + + int startIdx = str.charAt(0) == '\'' ? 1 : 0; + int endIdx = str.charAt(str.length() - 1) == '\'' ? str.length() - 1 : str.length(); + return str.substring(startIdx, endIdx); + } + static void initFileAssociationsTestFile(Path testFile) { try { // Write something in test file. @@ -995,6 +1095,11 @@ private static boolean isRpm() { } } + private static final class DesktopFileValidateAvailable { + + static final boolean VALUE = Result.of(Executor.of("desktop-file-validate", "-h")::executeWithoutExitCodeCheck).hasValue(); + } + private static final Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); // Values grabbed from https://linux.die.net/man/1/xdg-icon-resource diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryFileValidatorTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryFileValidatorTest.java new file mode 100644 index 000000000000..09c7bfb97944 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryFileValidatorTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.test.mock.CommandActionSpec; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.CommandMockExit; +import jdk.jpackage.test.mock.ToolProviderCommandMock; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class DesktopEntryFileValidatorTest { + + @ParameterizedTest + @EnumSource(value = CommandMockExit.class) + void test_createDefault(CommandMockExit exit) { + + var validator = DesktopEntryFileValidator.createDefault(); + + var counter = new AtomicInteger(); + + ThrowingRunnable incremeter = counter::getAndIncrement; + + ToolProviderCommandMock desktop_file_validate = CommandActionSpecs.build() + .action(CommandActionSpec.create("increment counter", incremeter)) + .exit(exit) + .toCommandMockBuilder().name("desktop-file-validate-mock").create(); + + final int validateCount = 10; + + Globals.main(() -> { + Globals.instance().executorFactory(() -> { + return new Executor().mapper(executor -> { + return executor.copy().mapper(null).toolProvider(desktop_file_validate); + }); + }); + + IntStream.range(0, validateCount).forEach(_ -> { + var result = validator.validate(Path.of("foo.desktop")); + switch (exit) { + case SUCCEED -> assertEquals(0, result.getExitCode()); + case EXIT_1 -> assertEquals(1, result.getExitCode()); + case THROW_MOCK_IO_EXCEPTION -> assertThrowsExactly(IllegalStateException.class, result::getExitCode); + } + }); + + switch (exit) { + case SUCCEED, EXIT_1 -> assertEquals(validateCount, counter.get()); + case THROW_MOCK_IO_EXCEPTION -> assertEquals(1, counter.get()); + } + + return 0; + }); + } +} diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryTest.java new file mode 100644 index 000000000000..d9fd723c3535 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/DesktopEntryTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class DesktopEntryTest { + + @ParameterizedTest + @CsvSource({ + "MIME_TYPE,MimeType", + "NAME,Name", + "COMMENT,Comment", + "EXEC,Exec", + "PATH,Path", + "ICON,Icon", + "TERMINAL,Terminal", + "TYPE,Type", + "CATEGORIES,Categories", + }) + void test_entryKey(DesktopEntry entry, String expectedKey) { + assertEquals(expectedKey, entry.entryKey()); + } + + @ParameterizedTest + @CsvSource({ + "MIME_TYPE,,", + "MIME_TYPE,foo,foo;", + "MIME_TYPE,foo;,foo;", + "MIME_TYPE,'',;", + + "NAME,,", + "NAME,Hello Duke!,Hello Duke!", + "NAME,'',''", + + "COMMENT,,", + "COMMENT,Hello Duke!,Hello Duke!", + "COMMENT,'',''", + + "EXEC,,", + "EXEC,foo/bar,foo/bar", + "EXEC,Hello Duke!,\"Hello Duke!\"", + "EXEC,'',''", + + "PATH,,", + "PATH,foo/bar,foo/bar", + "PATH,Hello Duke!,Hello Duke!", + "PATH,'',''", + + "ICON,,", + "ICON,Hello Duke!,Hello Duke!", + "ICON,'',''", + + "TERMINAL,,", + "TERMINAL,Hello Duke!,Hello Duke!", + "TERMINAL,'',''", + + "TYPE,,", + "TYPE,Hello Duke!,Hello Duke!", + "TYPE,'',''", + + "CATEGORIES,,", + "CATEGORIES,foo,foo;", + "CATEGORIES,foo;,foo;", + "CATEGORIES,'',;", + }) + void test_formatDesktopFileEntryValue(DesktopEntry entry, String entryValue, String expectedFormattedValue) { + + if (entryValue != null) { + assertEquals(expectedFormattedValue, entry.formatDesktopFileEntryValue(entryValue)); + + assertEquals(entry.entryKey() + "=" + expectedFormattedValue, entry.formatDesktopFileEntry(entryValue)); + } else { + assertThrowsExactly(NullPointerException.class, () -> { + entry.formatDesktopFileEntryValue(entryValue); + }); + + assertThrowsExactly(NullPointerException.class, () -> { + entry.formatDesktopFileEntry(entryValue); + }); + } + } +} diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java new file mode 100644 index 000000000000..2a760bff2715 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.CommandOutputControl.Result; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; + +class LinuxPackageBuilderTest { + + @ParameterizedTest + @EnumSource(ValidationResult.class) + void test_menuGroupNameValidation(ValidationResult validationResult, @TempDir Path workDir) { + + var counter = new AtomicInteger(); + + var builder = dummy().menuGroupName("bar").probeMenuGroupNameFile(workDir.resolve("probe.desktop")).desktopEntryFileValidator(path -> { + assertEquals(workDir.resolve("probe.desktop"), path); + assertTrue(Files.isRegularFile(path)); + + counter.incrementAndGet(); + + return switch (validationResult) { + case SUCCESS -> Result.build().exitCode(0).create(); + case EXIT_1 -> Result.build().exitCode(1).create(); + case EXIT_2 -> Result.build().exitCode(2).create(); + case UNAVAILABLE -> Result.build().create(); + }; + }); + + switch (validationResult) { + case SUCCESS, UNAVAILABLE -> assertDoesNotThrow(builder::create); + case EXIT_1, EXIT_2 -> { + var ex = assertThrowsExactly(ConfigException.class, builder::create); + + assertEquals(I18N.format("error.parameter-invalid-value", "bar", "--linux-menu-group"), ex.getMessage()); + assertEquals(I18N.format("error.invalid-desktop-category.advice"), ex.getAdvice()); + + assertEquals(null, ex.getCause()); + } + } + + assertTrue(Files.isRegularFile(workDir.resolve("probe.desktop"))); + assertEquals(1, counter.get()); + } + + @Test + void test_menuGroupNameValidation_with_probe_file_is_directory(@TempDir Path workDir) throws IOException { + + Files.createDirectory(workDir.resolve("probe.desktop")); + + var builder = dummy().menuGroupName("bar").probeMenuGroupNameFile(workDir.resolve("probe.desktop")).desktopEntryFileValidator(_ -> { + throw new AssertionError(); + }); + + assertThrowsExactly(UncheckedIOException.class, builder::create); + + assertTrue(Files.isDirectory(workDir.resolve("probe.desktop"))); + } + + @ParameterizedTest + @MethodSource + void test_menuGroupNameValidation_skip( + boolean setMenuGroupName, + boolean setProbeMenuGroupNameFile, + boolean setDesktopEntryFileValidator, + @TempDir Path workDir) throws IOException { + + Files.createDirectory(workDir.resolve("probe.desktop")); + + var builder = dummy(); + + if (setMenuGroupName) { + builder.menuGroupName("bar"); + } + + if (setProbeMenuGroupNameFile) { + builder.probeMenuGroupNameFile(workDir.resolve("probe.desktop")); + } + + if (setDesktopEntryFileValidator) { + builder.desktopEntryFileValidator(_ -> { + throw new AssertionError(); + }); + } + + assertDoesNotThrow(builder::create); + + assertTrue(Files.isDirectory(workDir.resolve("probe.desktop"))); + } + + static Collection test_menuGroupNameValidation_skip() { + + var testCases = new ArrayList(); + + for (var setMenuGroupName : List.of(true, false)) { + for (var setProbeMenuGroupNameFile : List.of(true, false)) { + for (var setDesktopEntryFileValidator : List.of(true, false)) { + if (Stream.of(setMenuGroupName, setProbeMenuGroupNameFile, setDesktopEntryFileValidator).allMatch(Boolean.TRUE::equals)) { + continue; + } + + testCases.add(Arguments.of(setMenuGroupName, setProbeMenuGroupNameFile, setDesktopEntryFileValidator)); + } + } + } + + return testCases; + } + + enum ValidationResult { + SUCCESS, + EXIT_1, + EXIT_2, + UNAVAILABLE, + ; + } + + private static LinuxPackageBuilder dummy() { + var app = new Application.Stub( + "foo", + "Foo App", + null, + null, + null, + List.of(), + List.of(), + List.of(), + ApplicationLayout.build().setAll("").create(), + Optional.empty(), + List.of(), + Map.of()); + + return new LinuxPackageBuilder(new PackageBuilder(app, StandardPackageType.LINUX_DEB)).arch(new LinuxPackageArch("acme")); + } +} diff --git a/test/jdk/tools/jpackage/junit/linux/junit.java b/test/jdk/tools/jpackage/junit/linux/junit.java index ba06cb30db77..51409f2b3d1c 100644 --- a/test/jdk/tools/jpackage/junit/linux/junit.java +++ b/test/jdk/tools/jpackage/junit/linux/junit.java @@ -62,3 +62,29 @@ * jdk/jpackage/internal/LinuxPackageArchTest.java * @run junit jdk.jpackage/jdk.jpackage.internal.LinuxPackageArchTest */ + +/* @test + * @summary Test LinuxPackageBuilder + * @requires (os.family == "linux") + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/LinuxPackageBuilderTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.LinuxPackageBuilderTest + */ + +/* @test + * @summary Test DesktopEntry + * @requires (os.family == "linux") + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/DesktopEntryTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.DesktopEntryTest + */ + +/* @test + * @summary Test DesktopEntryFileValidator + * @requires (os.family == "linux") + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.mock.* + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/DesktopEntryFileValidatorTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.DesktopEntryFileValidatorTest + */ diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index 52da229afa74..0a9668c0ec74 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -15,7 +15,13 @@ ErrorTest.test(IMAGE; app-desc=Hello; args-del=[--main-class]; errors=[message.e ErrorTest.test(IMAGE; args-add=[--module, com.foo.bar, --runtime-image, @@JAVA_HOME@@]; errors=[message.error-header+[error.no-module-in-path, com.foo.bar]]) ErrorTest.test(IMAGE; args-add=[--module, java.base, --runtime-image, @@JAVA_HOME@@]; errors=[message.error-header+[ERR_NoMainClass]]) ErrorTest.test(LINUX_DEB; app-desc=Hello; args-add=[--linux-package-name, #]; errors=[message.error-header+[error.deb-invalid-value-for-package-name, #], message.advice-header+[error.deb-invalid-value-for-package-name.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--linux-menu-group, %$@#!]; errors=[message.error-header+[error.parameter-invalid-value, %$@#!, --linux-menu-group], message.advice-header+[error.invalid-desktop-category.advice]]) ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--linux-package-name, #]; errors=[message.error-header+[error.rpm-invalid-value-for-package-name, #], message.advice-header+[error.rpm-invalid-value-for-package-name.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--runtime-image, @@FAKE_RUNTIME@@, --linux-shortcut, --name, Wake, --resource-dir, @@RESOURCE_DIR@@, --temp, @@EMPTY_DIR@@, --resource-dir, @@LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE@@, --resource-dir, @@LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --add-launcher, Zoo=@@ADD_LAUNCHER_PROPERTY_FILE@@, --add-launcher, Foo=@@ADD_LAUNCHER_PROPERTY_FILE@@]; args-del=[--name]; errors=[message.error-header+[error.invalid-desktop-entry-file.main-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Wake.desktop], message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Zoo.desktop, Zoo], message.advice-header+[error.invalid-desktop-entry-file.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--runtime-image, @@FAKE_RUNTIME@@, --linux-shortcut, --name, Wake, --resource-dir, @@RESOURCE_DIR@@, --temp, @@EMPTY_DIR@@, --resource-dir, @@LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE@@, --resource-dir, @@LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --resource-dir, @@LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --add-launcher, Zoo=@@ADD_LAUNCHER_PROPERTY_FILE@@, --add-launcher, Foo=@@ADD_LAUNCHER_PROPERTY_FILE@@]; args-del=[--name]; errors=[message.error-header+[error.invalid-desktop-entry-file.main-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Wake.desktop], message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Foo.desktop, Foo], message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Zoo.desktop, Zoo], message.advice-header+[error.invalid-desktop-entry-file.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--runtime-image, @@FAKE_RUNTIME@@, --linux-shortcut, --name, Wake, --resource-dir, @@RESOURCE_DIR@@, --temp, @@EMPTY_DIR@@, --resource-dir, @@LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE@@]; args-del=[--name]; errors=[message.error-header+[error.invalid-desktop-entry-file.main-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Wake.desktop], message.advice-header+[error.invalid-desktop-entry-file.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--runtime-image, @@FAKE_RUNTIME@@, --linux-shortcut, --name, Wake, --resource-dir, @@RESOURCE_DIR@@, --temp, @@EMPTY_DIR@@, --resource-dir, @@LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --add-launcher, Foo=@@ADD_LAUNCHER_PROPERTY_FILE@@]; args-del=[--name]; errors=[message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Foo.desktop, Foo], message.advice-header+[error.invalid-desktop-entry-file.advice]]) +ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--runtime-image, @@FAKE_RUNTIME@@, --linux-shortcut, --name, Wake, --resource-dir, @@RESOURCE_DIR@@, --temp, @@EMPTY_DIR@@, --resource-dir, @@LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --resource-dir, @@LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE@@, --add-launcher, Zoo=@@ADD_LAUNCHER_PROPERTY_FILE@@, --add-launcher, Foo=@@ADD_LAUNCHER_PROPERTY_FILE@@]; args-del=[--name]; errors=[message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Foo.desktop, Foo], message.error-header+[error.invalid-desktop-entry-file.add-launcher, @@EMPTY_DIR@@/image/opt/wake/lib/wake-Zoo.desktop, Zoo], message.advice-header+[error.invalid-desktop-entry-file.advice]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--mac-app-store, --runtime-image, @@JAVA_HOME@@]; errors=[message.error-header+[error.invalid-runtime-image-bin-dir, @@JAVA_HOME@@], message.advice-header+[error.invalid-runtime-image-bin-dir.advice, --mac-app-store]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@EMPTY_DIR@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@EMPTY_DIR@@, lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_BUNDLE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_BUNDLE@@, Contents/Home/lib/**/libjli.dylib]]) @@ -38,16 +44,16 @@ ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--app-version, 256.1]; errors= ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--launcher-as-service]; errors=[message.error-header+[error.missing-service-installer], message.advice-header+[error.missing-service-installer.advice]]) ErrorTest.test(args-add=[@foo]; errors=[message.error-header+[ERR_CannotParseOptions, foo]]) ErrorTest.testMacSignAppStoreInvalidRuntime -ErrorTest.testMacSignWithoutIdentity(IMAGE; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(IMAGE; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(MAC_DMG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(MAC_DMG; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN], message.error-header+[error.cert.not.found, INSTALLER, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@]; args-del=[--name]; errors=[message.error-header+[error.cert.not.found, INSTALLER, KEYCHAIN_WITH_APP_IMAGE_CERT]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_PKG_CERT@@]; args-del=[--name]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, KEYCHAIN_WITH_PKG_CERT]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN], message.error-header+[error.cert.not.found, INSTALLER, EMPTY_KEYCHAIN]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@, --app-image, @@APP_IMAGE_WITH_SHORT_NAME@@]; errors=[message.error-header+[error.cert.not.found, INSTALLER, KEYCHAIN_WITH_APP_IMAGE_CERT]]) -ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_PKG_CERT@@, --app-image, @@APP_IMAGE_WITH_SHORT_NAME@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, KEYCHAIN_WITH_PKG_CERT]]) +ErrorTest.testMacSignWithoutIdentity(IMAGE; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(IMAGE; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_DMG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_DMG; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@], message.error-header+[error.cert.not.found, INSTALLER, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@]; args-del=[--name]; errors=[message.error-header+[error.cert.not.found, INSTALLER, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_PKG_CERT@@]; args-del=[--name]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@KEYCHAIN_WITH_PKG_CERT@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@EMPTY_KEYCHAIN@@], message.error-header+[error.cert.not.found, INSTALLER, @@EMPTY_KEYCHAIN@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@, --app-image, @@APP_IMAGE_WITH_SHORT_NAME@@]; errors=[message.error-header+[error.cert.not.found, INSTALLER, @@KEYCHAIN_WITH_APP_IMAGE_CERT@@]]) +ErrorTest.testMacSignWithoutIdentity(MAC_PKG; args-add=[--mac-sign, --mac-signing-keychain, @@KEYCHAIN_WITH_PKG_CERT@@, --app-image, @@APP_IMAGE_WITH_SHORT_NAME@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, @@KEYCHAIN_WITH_PKG_CERT@@]]) ErrorTest.testMacSigningIdentityValidation(IMAGE, --mac-app-image-sign-identity, true) ErrorTest.testMacSigningIdentityValidation(IMAGE, --mac-signing-key-user-name, false) ErrorTest.testMacSigningIdentityValidation(MAC_DMG, --mac-app-image-sign-identity, true) diff --git a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java index 2591d1d393a4..870d8c2cbe17 100644 --- a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java +++ b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public static void testAdditionaltLaunchers() { */ @Test public static void testDesktopFileFromResourceDir() throws IOException { - final String expectedVersionString = "Version=12345678"; + final String expectedTryExecDesktopEntry = "TryExec=notify-send"; final Path tempDir = TKit.createTempDirectory("resources"); @@ -169,13 +169,13 @@ public static void testDesktopFileFromResourceDir() throws IOException { "Comment=APPLICATION_DESCRIPTION", "Icon=APPLICATION_ICON", "Categories=DEPLOY_BUNDLE_CATEGORY", - expectedVersionString + expectedTryExecDesktopEntry )); }) .addInstallVerifier(cmd -> { Path desktopFile = LinuxHelper.getDesktopFile(cmd); TKit.assertFileExists(desktopFile); - TKit.assertTextStream(expectedVersionString) + TKit.assertTextStream(expectedTryExecDesktopEntry) .label(String.format("[%s] file", desktopFile)) .predicate(String::equals) .apply(Files.readAllLines(desktopFile)); diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index b22ca5519ad8..fabe2f0c84aa 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -47,6 +47,7 @@ import jdk.jpackage.test.Executor; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.JPackageOutputValidator; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.JavaAppDesc; @@ -448,6 +449,7 @@ public void testTemp(TestTempType type) throws IOException { if (TestTempType.TEMPDIR_NOT_EMPTY.equals(type)) { pkgTest.setExpectedExitCode(1).addInitializer(cmd -> { + cmd.enableMessageCategories(MessageCategory.ERRORS); cmd.validateErr(JPackageCommand.makeError( "error.parameter-not-empty-directory", cmd.getArgumentValue("--temp"), "--temp")); }).addBundleVerifier(cmd -> { diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 77d4de40c1a4..8a5911ff21b1 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -62,6 +62,7 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageOutputValidator; import jdk.jpackage.test.JavaTool; +import jdk.jpackage.test.LinuxHelper; import jdk.jpackage.test.MacSign; import jdk.jpackage.test.MacSign.CertificateRequest; import jdk.jpackage.test.MacSign.CertificateType; @@ -167,10 +168,41 @@ enum Token { EMPTY_DIR(() -> { return TKit.createTempDirectory("empty-dir"); }), - ADD_LAUNCHER_PROPERTY_FILE, + ADD_LAUNCHER_PROPERTY_FILE(() -> { + final Path propsFile = TKit.createTempFile("add-launcher.properties"); + TKit.createPropertiesFile(propsFile, Map.of()); + return propsFile; + }), EMPTY_KEYCHAIN, KEYCHAIN_WITH_APP_IMAGE_CERT, KEYCHAIN_WITH_PKG_CERT, + RESOURCE_DIR(toFunction(cmd -> { + return TKit.createTempDirectory("resources"); + })), + FAKE_RUNTIME(toFunction(cmd -> { + return JPackageCommand.createInputRuntimeImage(JPackageCommand.RuntimeImageType.RUNTIME_TYPE_FAKE); + })), + LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE(toFunction(cmd -> { + var resourceDir = Path.of(cmd.getArgumentValue("--resource-dir")); + TKit.createTextFile(resourceDir.resolve(cmd.mainLauncherName() + ".desktop"), List.of( + "Version=12345" + )); + return resourceDir; + })), + LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE(toFunction(cmd -> { + var resourceDir = Path.of(cmd.getArgumentValue("--resource-dir")); + TKit.createTextFile(resourceDir.resolve("Foo.desktop"), List.of( + "Version=54321" + )); + return resourceDir; + })), + LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE(toFunction(cmd -> { + var resourceDir = Path.of(cmd.getArgumentValue("--resource-dir")); + TKit.createTextFile(resourceDir.resolve("Zoo.desktop"), List.of( + "Version=777" + )); + return resourceDir; + })), ; private Token() { @@ -187,7 +219,8 @@ private Token(Supplier valueSupplier) { }); } - String token() { + @Override + public String toString() { return makeToken(name()); } @@ -205,7 +238,7 @@ private static String makeToken(String v) { } private final Optional> valueSupplier; - private final TokenReplace tokenReplace = new TokenReplace(token()); + private final TokenReplace tokenReplace = new TokenReplace(toString()); } record PackageTypeSpec(Optional type, boolean anyNativeType) implements CannedArgument { @@ -405,6 +438,11 @@ Builder unsupportedPlatformOption(String arg, String ... otherArgs) { return addArgs(arg).addArgs(otherArgs).error("ERR_UnsupportedOption", arg); } + Builder mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + TestSpec create() { return new TestSpec( Optional.ofNullable(type), @@ -450,7 +488,7 @@ void test(Map> tokenValueSuppliers) { removeArgs.forEach(cmd::removeArgumentWithValue); cmd.addArguments(addArgs); - final var tokenValueSupplier = TokenReplace.createCachingTokenValueSupplier(Stream.of(Token.values()).collect(toMap(Token::token, token -> { + final var tokenValueSupplier = TokenReplace.createCachingTokenValueSupplier(Stream.of(Token.values()).collect(toMap(Token::toString, token -> { return () -> { return token.expand(cmd).orElseGet(() -> { final var tvs = Objects.requireNonNull(tokenValueSuppliers.get(token), () -> { @@ -468,6 +506,24 @@ void test(Map> tokenValueSuppliers) { cmd.clearArguments().addArguments(newArgs); } + var resolvedExpectedMessages = expectedMessages.stream().map(cannedMessage -> { + return new CannedFormattedString( + cannedMessage.formatter(), + cannedMessage.format(), + cannedMessage.args().stream().map(arg -> { + return switch (arg) { + case String str -> { + for (final var token : Token.values()) { + str = token.asTokenReplace().applyTo(str, tokenValueSupplier); + } + yield str; + } + case Token tkn -> tokenValueSupplier.apply(tkn.toString()); + default -> arg; + }; + }).toList()); + }).toList(); + // Disable default logic adding `--verbose` option // to jpackage command line. // It will affect jpackage error messages if the command line is malformed. @@ -477,7 +533,7 @@ void test(Map> tokenValueSuppliers) { // with jpackage arguments in this test. cmd.ignoreDefaultRuntime(true); - var validator = new JPackageOutputValidator().stderr().expectMatchingStrings(expectedMessages).match(match); + var validator = new JPackageOutputValidator().stderr().expectMatchingStrings(resolvedExpectedMessages).match(match); if (match) { new JPackageOutputValidator().stdout().validateEndOfStream().applyTo(cmd); } @@ -562,10 +618,10 @@ public static Collection basic() { testSpec().appDesc("com.other/com.other.Hello").removeArgs("--module-path") .error("ERR_MissingArgument2", "--runtime-image", "--module-path"), // no main class in module path - testSpec().noAppDesc().addArgs("--module", "java.base", "--runtime-image", Token.JAVA_HOME.token()) + testSpec().noAppDesc().addArgs("--module", "java.base", "--runtime-image", Token.JAVA_HOME.toString()) .error("ERR_NoMainClass"), // no module in module path - testSpec().noAppDesc().addArgs("--module", "com.foo.bar", "--runtime-image", Token.JAVA_HOME.token()) + testSpec().noAppDesc().addArgs("--module", "com.foo.bar", "--runtime-image", Token.JAVA_HOME.toString()) .error("error.no-module-in-path", "com.foo.bar"), // non-existing argument file testSpec().noAppDesc().notype().addArgs("@foo") @@ -606,7 +662,7 @@ String[] asArray() { private static List createRuntimeMutuallyExclusive(String arg, String... otherArgs) { return createMutuallyExclusive( - new ArgumentGroup("--runtime-image", Token.JAVA_HOME.token()), + new ArgumentGroup("--runtime-image", Token.JAVA_HOME.toString()), new ArgumentGroup(arg, otherArgs) ).map(TestSpec.Builder::noAppDesc).map(TestSpec.Builder::nativeType).map(TestSpec.Builder::create).toList(); } @@ -638,6 +694,7 @@ public static Collection invalidAppVersion() { @Test @ParameterSupplier("basic") @ParameterSupplier("testRuntimeInstallerInvalidOptions") + @ParameterSupplier("testAdditionLaunchers") @ParameterSupplier(value="testWindows", ifOS = WINDOWS) @ParameterSupplier(value="testMac", ifOS = MACOS) @ParameterSupplier(value="testLinux", ifOS = LINUX) @@ -667,7 +724,7 @@ public static Collection testRuntimeInstallerInvalidOptions() { return toTestArgs(argsStream.map(args -> { var builder = testSpec().noAppDesc().nativeType() - .addArgs("--runtime-image", Token.JAVA_HOME.token()) + .addArgs("--runtime-image", Token.JAVA_HOME.toString()) .addArgs(args); if (args.contains("--add-modules")) { builder.error("ERR_MutuallyExclusiveOptions", "--runtime-image", "--add-modules"); @@ -676,27 +733,11 @@ public static Collection testRuntimeInstallerInvalidOptions() { })); } - @Test - @ParameterSupplier - public static void testAdditionLaunchers(TestSpec spec) { - final Path propsFile = TKit.createTempFile("add-launcher.properties"); - TKit.createPropertiesFile(propsFile, Map.of()); - spec.mapExpectedMessages(cannedStr -> { - return cannedStr.mapArgs(arg -> { - if (arg == Token.ADD_LAUNCHER_PROPERTY_FILE) { - return propsFile; - } else { - return arg; - } - }); - }).test(Map.of(Token.ADD_LAUNCHER_PROPERTY_FILE, cmd -> propsFile)); - } - public static Collection testAdditionLaunchers() { return toTestArgs(Stream.of( - testSpec().addArgs("--add-launcher", Token.ADD_LAUNCHER_PROPERTY_FILE.token()) + testSpec().addArgs("--add-launcher", Token.ADD_LAUNCHER_PROPERTY_FILE.toString()) .error("error.parameter-add-launcher-malformed", Token.ADD_LAUNCHER_PROPERTY_FILE, "--add-launcher"), - testSpec().removeArgs("--name").addArgs("--name", "foo", "--add-launcher", "foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE.token()) + testSpec().removeArgs("--name").addArgs("--name", "foo", "--add-launcher", "foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE.toString()) .error("error.launcher-duplicate-name", "foo") )); } @@ -750,7 +791,7 @@ public static void testMacSignWithoutIdentity(TestSpec spec) { }); } - private static void testMacSignWithoutIdentityWithNewTKitState(TestSpec spec) { + private static void testMacSignWithoutIdentityWithNewTKitState(TestSpec spec) { final Token keychainToken = spec.expectedMessages().stream().flatMap(cannedStr -> { return cannedStr.args().stream().filter(Token.class::isInstance).map(Token.class::cast).filter(token -> { switch (token) { @@ -833,8 +874,8 @@ private static void testMacSignWithoutIdentityWithNewTKitState(TestSpec spec) { public static Collection testMacSignWithoutIdentity() { final List testCases = new ArrayList<>(); - final var signArgs = List.of("--mac-sign", "--mac-signing-keychain", Token.EMPTY_KEYCHAIN.token()); - final var appImageArgs = List.of("--app-image", Token.APP_IMAGE_WITH_SHORT_NAME.token()); + final var signArgs = List.of("--mac-sign", "--mac-signing-keychain", Token.EMPTY_KEYCHAIN.toString()); + final var appImageArgs = List.of("--app-image", Token.APP_IMAGE_WITH_SHORT_NAME.toString()); for (var withAppImage : List.of(true, false)) { var builder = testSpec(); @@ -869,7 +910,7 @@ public static Collection testMacSignWithoutIdentity() { public static Collection testMacPkgSignWithoutIdentity() { final List testCases = new ArrayList<>(); - final var appImageArgs = List.of("--app-image", Token.APP_IMAGE_WITH_SHORT_NAME.token()); + final var appImageArgs = List.of("--app-image", Token.APP_IMAGE_WITH_SHORT_NAME.toString()); for (var withAppImage : List.of(true, false)) { for (var existingCertType : CertificateType.values()) { @@ -887,7 +928,7 @@ public static Collection testMacPkgSignWithoutIdentity() { var builder = testSpec() .type(PackageType.MAC_PKG) - .addArgs("--mac-sign", "--mac-signing-keychain", keychain.token()) + .addArgs("--mac-sign", "--mac-signing-keychain", keychain.toString()) .error("error.cert.not.found", missingCertificateNamePrefix, keychain); if (withAppImage) { @@ -925,8 +966,8 @@ public static void testInvalidAppName(InvalidName name) { @Test @ParameterSupplier("invalidNames") public static void testInvalidAddLauncherName(InvalidName name) { - testAdditionLaunchers(testSpec() - .addArgs("--add-launcher", name + "=" + Token.ADD_LAUNCHER_PROPERTY_FILE.token()) + test(testSpec() + .addArgs("--add-launcher", name + "=" + Token.ADD_LAUNCHER_PROPERTY_FILE.toString()) .error("ERR_InvalidSLName", adjustTextStreamVerifierArg(name.value())) .match(!name.isMessingUpConsoleOutput()) .create()); @@ -1003,7 +1044,7 @@ public static Collection testMac() { testSpec().type(PackageType.MAC_DMG).invalidTypeArg("--mac-installer-sign-identity", "foo"), testSpec().invalidTypeArg("--mac-dmg-content", "foo"), testSpec().type(PackageType.MAC_PKG).invalidTypeArg("--mac-dmg-content", "foo"), - testSpec().noAppDesc().addArgs("--app-image", Token.APP_IMAGE.token()) + testSpec().noAppDesc().addArgs("--app-image", Token.APP_IMAGE.toString()) .error("error.app-image.mac-sign.required"), testSpec().type(PackageType.MAC_PKG).addArgs("--mac-package-identifier", "#1") .error("error.parameter-not-mac-bundle-identifier", "#1", "--mac-package-identifier") @@ -1012,14 +1053,12 @@ public static Collection testMac() { testSpec().nativeType().addArgs("--mac-app-store", "--jlink-options", "--bind-services") .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands"), // Predefined app image must be a valid macOS bundle. - testSpec().noAppDesc().nativeType().addArgs("--app-image", Token.EMPTY_DIR.token()) - .error("error.parameter-not-mac-bundle", JPackageCommand.cannedArgument(cmd -> { - return Path.of(cmd.getArgumentValue("--app-image")); - }, Token.EMPTY_DIR.token()), "--app-image"), - testSpec().nativeType().noAppDesc().addArgs("--app-image", Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.token()) + testSpec().noAppDesc().nativeType().addArgs("--app-image", Token.EMPTY_DIR.toString()) + .error("error.parameter-not-mac-bundle", Token.EMPTY_DIR, "--app-image"), + testSpec().nativeType().noAppDesc().addArgs("--app-image", Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.toString()) .error("error.invalid-app-image-plist-file", JPackageCommand.cannedArgument(cmd -> { return new MacBundle(Path.of(cmd.getArgumentValue("--app-image"))).infoPlistFile(); - }, Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.token())) + }, Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.toString())) ).map(TestSpec.Builder::create).toList()); macInvalidRuntime(testCases::add); @@ -1032,7 +1071,7 @@ public static Collection testMac() { var withoutSign = testSpec() .noAppDesc() .addArgs(argGroup.asArray()) - .addArgs("--app-image", Token.APP_IMAGE.token()); + .addArgs("--app-image", Token.APP_IMAGE.toString()); var withSign = withoutSign.copy().addArgs("--mac-sign"); @@ -1100,6 +1139,82 @@ public static Collection testLinux() { .advice("error.rpm-invalid-value-for-package-name.advice") ).map(TestSpec.Builder::create).toList()); + if (LinuxHelper.isDesktopFileValidateCommandAvailable()) { + Stream.of( + testSpec().type(PackageType.LINUX_RPM).addArgs("--linux-menu-group", "%$@#!") + .error("error.parameter-invalid-value", "%$@#!", "--linux-menu-group") + .advice("error.invalid-desktop-category.advice") + ).map(TestSpec.Builder::create).forEach(testCases::add); + + Consumer desktopValidatorInitializer = builder -> { + builder.type(PackageType.LINUX_RPM) + .addArgs("--runtime-image", Token.FAKE_RUNTIME.toString()) + .addArgs("--linux-shortcut") + .removeArgs("--name").addArgs("--name", "Wake") + .addArgs("--resource-dir", Token.RESOURCE_DIR.toString()) + .addArgs("--temp", Token.EMPTY_DIR.toString()); + }; + + // Invalid desktop entry files + Stream.of( + // Invalid main desktop entry file + testSpec().mutate(desktopValidatorInitializer) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .error("error.invalid-desktop-entry-file.main-launcher", + String.format("%s/image/opt/wake/lib/wake-Wake.desktop", Token.EMPTY_DIR)) + .advice("error.invalid-desktop-entry-file.advice"), + // Valid main desktop entry file, invalid additional launcher desktop file + testSpec().mutate(desktopValidatorInitializer) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--add-launcher", "Foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE.toString()) + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Foo.desktop", Token.EMPTY_DIR), + "Foo") + .advice("error.invalid-desktop-entry-file.advice"), + // Invalid main desktop entry file, valid additional launcher desktop file and one of additional launchers + testSpec().mutate(desktopValidatorInitializer) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--add-launcher", "Zoo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .addArgs("--add-launcher", "Foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .error("error.invalid-desktop-entry-file.main-launcher", + String.format("%s/image/opt/wake/lib/wake-Wake.desktop", Token.EMPTY_DIR)) + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Zoo.desktop", Token.EMPTY_DIR), + "Zoo") + .advice("error.invalid-desktop-entry-file.advice"), + // Main desktop entry file and all additional launcher desktop files invalid + testSpec().mutate(desktopValidatorInitializer) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--add-launcher", "Zoo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .addArgs("--add-launcher", "Foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .error("error.invalid-desktop-entry-file.main-launcher", + String.format("%s/image/opt/wake/lib/wake-Wake.desktop", Token.EMPTY_DIR)) + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Foo.desktop", Token.EMPTY_DIR), + "Foo") + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Zoo.desktop", Token.EMPTY_DIR), + "Zoo") + .advice("error.invalid-desktop-entry-file.advice"), + // All additional launcher desktop files invalid + testSpec().mutate(desktopValidatorInitializer) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_ZOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--resource-dir", Token.LINUX_ADD_INVALID_FOO_DESKTOP_ENTRY_FILE_RESOURCE.toString()) + .addArgs("--add-launcher", "Zoo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .addArgs("--add-launcher", "Foo=" + Token.ADD_LAUNCHER_PROPERTY_FILE) + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Foo.desktop", Token.EMPTY_DIR), + "Foo") + .error("error.invalid-desktop-entry-file.add-launcher", + String.format("%s/image/opt/wake/lib/wake-Zoo.desktop", Token.EMPTY_DIR), + "Zoo") + .advice("error.invalid-desktop-entry-file.advice") + ).map(TestSpec.Builder::create).forEach(testCases::add); + } + invalidShortcut(testCases::add, "--linux-shortcut"); return toTestArgs(testCases.stream()); @@ -1161,14 +1276,12 @@ private static void invalidShortcut(Consumer accumulator, String short private static void macInvalidRuntime(Consumer accumulator) { var runtimeWithBinDirErr = makeError( - "error.invalid-runtime-image-bin-dir", JPackageCommand.cannedArgument(cmd -> { - return Path.of(cmd.getArgumentValue("--runtime-image")); - }, Token.JAVA_HOME.token())); + "error.invalid-runtime-image-bin-dir", Token.JAVA_HOME); var runtimeWithBinDirErrAdvice = makeAdvice( "error.invalid-runtime-image-bin-dir.advice", "--mac-app-store"); Stream.of( - testSpec().nativeType().addArgs("--mac-app-store", "--runtime-image", Token.JAVA_HOME.token()) + testSpec().nativeType().addArgs("--mac-app-store", "--runtime-image", Token.JAVA_HOME.toString()) .messages(runtimeWithBinDirErr, runtimeWithBinDirErrAdvice) ).map(TestSpec.Builder::create).forEach(accumulator); @@ -1201,14 +1314,11 @@ static MissingRuntimeFileError missingLibjli(Token runtimeDir) { } TestSpec.Builder applyTo(TestSpec.Builder builder) { - return builder.addArgs("--runtime-image", runtimeDir.token()).messages(expectedErrorMsg()); + return builder.addArgs("--runtime-image", runtimeDir.toString()).messages(expectedErrorMsg()); } private CannedFormattedString expectedErrorMsg() { - return makeError( - "error.invalid-runtime-image-missing-file", JPackageCommand.cannedArgument(cmd -> { - return Path.of(cmd.getArgumentValue("--runtime-image")); - }, runtimeDir.token()), missingFile); + return makeError("error.invalid-runtime-image-missing-file", runtimeDir, missingFile); } } diff --git a/test/jdk/tools/jpackage/share/FileAssociationsTest.java b/test/jdk/tools/jpackage/share/FileAssociationsTest.java index 0af7e7a54ff3..f8d5443d77e3 100644 --- a/test/jdk/tools/jpackage/share/FileAssociationsTest.java +++ b/test/jdk/tools/jpackage/share/FileAssociationsTest.java @@ -31,6 +31,7 @@ import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.FileAssociations; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -149,6 +150,9 @@ private static PackageTest initPackageTest() { .excludeTypes(PackageType.MAC) .configureHelloApp() .addInitializer(JPackageCommand::setFakeRuntime) + .addInitializer(cmd -> { + cmd.enableMessageCategories(MessageCategory.ERRORS); + }) .setExpectedExitCode(1); } diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index d66a2fdebe9b..0ed92f9d1978 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -327,7 +327,7 @@ private void initTest(ConfigurationTarget target) { cmd.saveConsoleOutput(true); cmd.setFakeRuntime(); cmd.addArguments(extraJPackageArgs); - cmd.setEnabledMessageCategories(MessageCategory.RESOURCES).setDisabledMessageCategories(); + cmd.enableMessageCategories(MessageCategory.RESOURCES).setDisabledMessageCategories(); }); } diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 4d5c19791908..0d11865004de 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -29,6 +29,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; @@ -103,6 +104,7 @@ public static void testLinuxInvalid(String installDir) { .addInitializer(cmd -> { cmd.addArguments("--install-dir", installDir); cmd.validateErr(JPackageCommand.makeError("error.invalid-install-dir", installDir)); + cmd.enableMessageCategories(MessageCategory.ERRORS); }) .run(); } diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index ab4dfe1e1fa3..635d5e4fc6fa 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -22,6 +22,8 @@ */ +import static jdk.jpackage.test.JPackageCommand.cannedArgument; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -35,17 +37,15 @@ import java.util.jar.JarFile; import java.util.stream.Collectors; import java.util.stream.Stream; - import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; -import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.CfgFile; import jdk.jpackage.test.Executor; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; -import static jdk.jpackage.test.JPackageCommand.cannedArgument; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.TKit; @@ -146,6 +146,7 @@ public MainClassTest(Script script) { cmd = JPackageCommand .helloAppImage(script.appDesc) + .enableMessageCategories(MessageCategory.ERRORS) .ignoreDefaultRuntime(true); if (!script.withJLink) { cmd.addArguments("--runtime-image", Path.of(System.getProperty( diff --git a/test/jdk/tools/jpackage/share/ModularAppTest.java b/test/jdk/tools/jpackage/share/ModularAppTest.java index d28753b4746f..8be817696da8 100644 --- a/test/jdk/tools/jpackage/share/ModularAppTest.java +++ b/test/jdk/tools/jpackage/share/ModularAppTest.java @@ -45,6 +45,7 @@ import jdk.jpackage.test.Executor; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.PackageType; @@ -279,6 +280,7 @@ void run() { "error.no-module-in-path", theAppDesc.moduleName()); } + cmd.enableMessageCategories(MessageCategory.ERRORS); cmd.validateErr(expectedErrorMessage).execute(1); } } diff --git a/test/jdk/tools/jpackage/share/OutputErrorTest.java b/test/jdk/tools/jpackage/share/OutputErrorTest.java index 28dca22a244b..686e45fa0dec 100644 --- a/test/jdk/tools/jpackage/share/OutputErrorTest.java +++ b/test/jdk/tools/jpackage/share/OutputErrorTest.java @@ -34,6 +34,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.MessageCategory; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.TKit; @@ -59,6 +60,7 @@ public void testPackage(ExistingOutputBundleType existingOutputBundleType) { new PackageTest().configureHelloApp().addInitializer(cmd -> { cmd.setFakeRuntime(); + cmd.enableMessageCategories(MessageCategory.ERRORS); cmd.setArgumentValue("--dest", TKit.createTempDirectory("output")); cmd.removeOldOutputBundle(false); cmd.validateErr(JPackageCommand.makeError( From 1612d17466dc3bc89f6cf34668897820b7d9e2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Mon, 31 Aug 2026 13:02:22 +0000 Subject: [PATCH 154/223] 8391298: JFR: Overscoping JfrEpochShift_lock Reviewed-by: egahlin --- .../checkpoint/jfrCheckpointManager.cpp | 2 -- .../recorder/service/jfrRecorderService.cpp | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index c1eded10f92b..3fd15d9aed4a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -38,7 +38,6 @@ #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" #include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" -#include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -507,7 +506,6 @@ void JfrCheckpointManager::shift_epoch() { DEBUG_ONLY(const u1 current_epoch = JfrTraceIdEpoch::current();) JfrTraceIdEpoch::shift_epoch(); assert(current_epoch != JfrTraceIdEpoch::current(), "invariant"); - JfrStringPool::on_epoch_shift(); } size_t JfrCheckpointManager::write() { diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 84c37e91df40..168af9a22e70 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -467,12 +467,15 @@ void JfrRecorderService::safepoint_clear() { _checkpoint_manager.notify_threads(true); JfrDeprecationManager::on_safepoint_clear(); JfrStackTraceRepository::clear(); - // Ensure that non-Java threads cannot perform tagging, enqueuing, - // or event writing that interleaves with the epoch shift. - ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); - _storage.clear(); - _chunkwriter.set_time_stamp(); - _checkpoint_manager.shift_epoch(); + { + // Ensure that non-Java threads cannot perform tagging, enqueuing, + // or event writing that interleaves with the epoch shift. + ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + _storage.clear(); + _chunkwriter.set_time_stamp(); + _checkpoint_manager.shift_epoch(); + } + JfrStringPool::on_epoch_shift(); } void JfrRecorderService::post_safepoint_clear() { @@ -581,12 +584,15 @@ void JfrRecorderService::safepoint_write() { _checkpoint_manager.on_rotation(); JfrDeprecationManager::on_safepoint_write(); write_stacktrace(_stack_trace_repository, _chunkwriter, true); - // Ensure that non-Java threads cannot perform tagging, enqueuing, - // or event writing that interleaves with the epoch shift. - ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); - _storage.write_at_safepoint(); - _chunkwriter.set_time_stamp(); - _checkpoint_manager.shift_epoch(); + { + // Ensure that non-Java threads cannot perform tagging, enqueuing, + // or event writing that interleaves with the epoch shift. + ConditionalMutexLocker lock(JfrEpochShift_lock, UseShenandoahGC || UseZGC, Mutex::_no_safepoint_check_flag); + _storage.write_at_safepoint(); + _chunkwriter.set_time_stamp(); + _checkpoint_manager.shift_epoch(); + } + JfrStringPool::on_epoch_shift(); } void JfrRecorderService::post_safepoint_write() { From 8fa26b94889911bfd3899bd60aed6b040414f105 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Mon, 31 Aug 2026 13:19:25 +0000 Subject: [PATCH 155/223] 8391431: RISC-V: AOTCodeTest.java fails after JDK-8388288 with fastdebug Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 260d31fc7cdc..7cefb1eef2c9 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -1240,8 +1240,8 @@ class StubGenerator: public StubCodeGenerator { void verify_oop_array(size_t size, Register a, Register count, Register temp) { Label loop, end; __ mv(t1, zr); - __ slli(t0, count, exact_log2(size)); __ bind(loop); + __ slli(t0, count, exact_log2(size)); __ bgeu(t1, t0, end); __ add(temp, a, t1); From ba89835a0a1bf9f0d30a38fdc68cf18ef3ea41aa Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 31 Aug 2026 16:33:46 +0000 Subject: [PATCH 156/223] 8391445: (dc) DatagramChannel.open fails with Linux build of JDK on BSD Reviewed-by: michaelm --- src/java.base/unix/native/libnio/ch/Net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c index 8fc3d11b5e78..ad0994aa3e72 100644 --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -297,10 +297,14 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, } #if defined(__linux__) - /* IPv4 or IPv6 datagram socket: disable IP_MULTICAST_ALL (Linux 2.6.31) */ + /* + * IPv4 or IPv6 datagram socket: disable IP_MULTICAST_ALL (Linux 2.6.31) + * Not supported by the Linux binary compatibility layer on BSD + */ if (type == SOCK_DGRAM && ipv4_available()) { int arg = 0; - if ((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0)) { + if ((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && + (errno != ENOPROTOOPT)) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Unable to set IP_MULTICAST_ALL"); From 70b48b9dab2ad618c5d5547c75698093b1821ea0 Mon Sep 17 00:00:00 2001 From: Yunbo Zhang Date: Mon, 31 Aug 2026 17:13:31 +0000 Subject: [PATCH 157/223] 8348737: PlatformProperties always triggers rebuild when cross compiling Reviewed-by: erikj --- make/modules/java.base/gensrc/GensrcMisc.gmk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk index edb5e8bc58ef..2c563f4bfd4f 100644 --- a/make/modules/java.base/gensrc/GensrcMisc.gmk +++ b/make/modules/java.base/gensrc/GensrcMisc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ else OPENJDK_TARGET_OS_CANONICAL := $(OPENJDK_TARGET_OS) endif -$(eval $(call SetupTextFileProcessing, BUILD_PLATFORMPROPERTIES_JAVA, \ +$(eval $(call SetupTextFileProcessing, BUILD_PLATFORMPROPERTIES_JAVA_$(OPENJDK_TARGET_OS)_$(OPENJDK_TARGET_CPU), \ SOURCE_FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template, \ OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/PlatformProps.java, \ REPLACEMENTS := \ @@ -82,7 +82,8 @@ $(eval $(call SetupTextFileProcessing, BUILD_PLATFORMPROPERTIES_JAVA, \ @@OPENJDK_TARGET_CPU_BITS@@ => $(OPENJDK_TARGET_CPU_BITS), \ )) -TARGETS += $(BUILD_VERSION_JAVA) $(BUILD_PLATFORMPROPERTIES_JAVA) +TARGETS += $(BUILD_VERSION_JAVA) \ + $(BUILD_PLATFORMPROPERTIES_JAVA_$(OPENJDK_TARGET_OS)_$(OPENJDK_TARGET_CPU)) ################################################################################ ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), ) From 0b28db76f05600afa64168ee301eb3e9f300f73d Mon Sep 17 00:00:00 2001 From: Frederic Parain Date: Mon, 31 Aug 2026 19:30:26 +0000 Subject: [PATCH 158/223] 8390471: [Valhalla] "assert(_sig_cc == nullptr) failed: Already initialized" with -XX:+TestAOTAdapterLinkFailure Reviewed-by: thartmann, chagedorn, jsjolen --- src/hotspot/share/runtime/sharedRuntime.cpp | 18 ++++++++++------- .../AOTCacheSupportForCustomLoaders.java | 20 +++++++++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index aaf9c956ca07..b770b638ff39 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3336,13 +3336,17 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterHandlerEntry* handler, allocate_code_blob); if (ces.has_scalarized_args()) { - // Save a C heap allocated version of the scalarized signature and store it in the adapter - GrowableArray* heap_sig = new (mtCode) GrowableArray(ces.sig_cc()->length(), mtCode); - heap_sig->appendAll(ces.sig_cc()); - handler->set_sig_cc(heap_sig); - heap_sig = new (mtCode) GrowableArray(ces.sig_cc_ro()->length(), mtCode); - heap_sig->appendAll(ces.sig_cc_ro()); - handler->set_sig_cc_ro(heap_sig); + assert((handler->get_sig_cc() == nullptr) == (handler->get_sig_cc_ro() == nullptr), "Inconsistency"); + // Check if scalarized signatures have to be initialized + if (handler->get_sig_cc() == nullptr) { + // Save a C heap allocated version of the scalarized signature and store it in the adapter + GrowableArray* heap_sig = new (mtCode) GrowableArray(ces.sig_cc()->length(), mtCode); + heap_sig->appendAll(ces.sig_cc()); + handler->set_sig_cc(heap_sig); + heap_sig = new (mtCode) GrowableArray(ces.sig_cc_ro()->length(), mtCode); + heap_sig->appendAll(ces.sig_cc_ro()); + handler->set_sig_cc_ro(heap_sig); + } } // On zero there is no code to save and no need to create a blob and // or relocate the handler. diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java index 9fef0845d1df..66d9936f5ce0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java @@ -25,8 +25,9 @@ /* * @test * @summary Test AOT cache support for array classes in custom class loaders. - * @bug 8353298 8356838 + * @bug 8353298 8356838 8390471 * @requires vm.cds.supports.aot.class.linking + * @enablePreview * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build ReturnIntegerAsString * @build AOTCacheSupportForCustomLoaders @@ -60,12 +61,23 @@ public static void main(String... args) throws Exception { String modulePath = modulePackager.getOutputDir().toString(); modulePackager.createModularJar("com.test"); - SimpleCDSAppTester.of("AOTCacheSupportForCustomLoaders") + test(modulePath, false); + test(modulePath, true); // Test case for JDK-8390471 + } + + static void test(String modulePath, boolean preview) throws Exception { + SimpleCDSAppTester tester = SimpleCDSAppTester.of("AOTCacheSupportForCustomLoaders") .classpath("app.jar") .addVmArgs("-Xlog:aot+class=debug", "-Xlog:aot", "-Xlog:cds", "--module-path=" + modulePath, - "--add-modules=com.test") - .appCommandLine("AppWithCustomLoaders", modulePath) + "--add-modules=com.test"); + if (preview) { + // Test case for JDK-8390471 + tester.addVmArgs("--enable-preview", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+TestAOTAdapterLinkFailure"); // TestAOTAdapterLinkFailure is a developer flag + } + tester.appCommandLine("AppWithCustomLoaders", modulePath) .setTrainingChecker((OutputAnalyzer out) -> { out.shouldContain("Skipping AppWithCustomLoaders$MyLoadeeC: Not loaded from \"file:\" code source") .shouldContain("Skipping AppWithCustomLoaders$MyLoadeeD: super AppWithCustomLoaders$MyLoadeeC is excluded") From 81f1e2232a99abaa40ed0afc10af2c289f36f01a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Aug 2026 19:53:27 +0000 Subject: [PATCH 159/223] 8391423: jpackage DEB packaging tests fail on RPM-based Linux Reviewed-by: almatvee --- .../helpers/jdk/jpackage/test/LinuxHelper.java | 16 ++++++++++------ .../tools/jpackage/linux/LinuxResourceTest.java | 7 +++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index b4d421c52e50..dd248f67d69b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1073,15 +1073,19 @@ private static final class NativePackageType { static final PackageType VALUE; private static boolean isDebian() { - // we are just going to run "dpkg -s coreutils" and assume Debian - // or derivative if no error is returned. - return Result.of(Executor.of("dpkg", "-s", "coreutils")::execute).hasValue(); + // Run "dpkg -s coreutils" command and assume this is native Debian-based Linux if it succeeds. + // If it fails to execute (command not found) or exits with an error (non-zero exit code), we assume the opposite. + return Result.of(Executor.of("dpkg", "-s", "coreutils")::executeWithoutExitCodeCheck).value().filter(result -> { + return result.getExitCode() == 0; + }).isPresent(); } private static boolean isRpm() { - // we are just going to run "rpm -q rpm" and assume RPM - // or derivative if no error is returned. - return Result.of(Executor.of("rpm", "-q", "rpm")::execute).hasValue(); + // Run "rpm -q rpm" command and assume this is native RPM-based Linux if it succeeds. + // If it fails to execute (command not found) or exits with an error (non-zero exit code), we assume the opposite. + return Result.of(Executor.of("rpm", "-q", "rpm")::executeWithoutExitCodeCheck).value().filter(result -> { + return result.getExitCode() == 0; + }).isPresent(); } static { diff --git a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java b/test/jdk/tools/jpackage/linux/LinuxResourceTest.java index 9915dfd64dce..778026885483 100644 --- a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java +++ b/test/jdk/tools/jpackage/linux/LinuxResourceTest.java @@ -78,10 +78,13 @@ public static void testHardcodedProperties() throws IOException { "Maintainer: APPLICATION_MAINTAINER", "Priority: optional", archProp.format(), - "Provides: dont-install-me", "Description: APPLICATION_DESCRIPTION", "Installed-Size: APPLICATION_INSTALLED_SIZE", - "Depends: PACKAGE_DEFAULT_DEPENDENCIES" + "Depends: PACKAGE_DEFAULT_DEPENDENCIES", + // The value of the last field must not be an empty string. + // Otherwise newer versions of dpkg-deb fails with + // "end of file before value of field 'Depends' (missing final newline)" error + "Provides: dont-install-me" )); cmd.excludeStandardAsserts(StandardAssert.LINUX_PACKAGE_ARCH); From d1f195ec503b12628f7508152f1c8a45b9753194 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 1 Sep 2026 00:10:44 +0000 Subject: [PATCH 160/223] 8391473: jpackage ignores exit code of the "dpkg-deb" command Reviewed-by: almatvee --- .../jpackage/internal/LinuxDebPackager.java | 2 +- .../jdk/jpackage/test/mock/ScriptSpec.java | 4 - .../internal/LinuxDebPackagerTest.java | 202 ++++++++++++++++++ .../jdk/tools/jpackage/junit/linux/junit.java | 11 + 4 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxDebPackagerTest.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java index 65efd9fc4c64..eb8a64139057 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java @@ -155,7 +155,7 @@ protected void buildPackage() throws IOException { // run dpkg Executor.of(cmdline).retryOnKnownErrorMessage( - "semop(1): encountered an error: Invalid argument").execute(); + "semop(1): encountered an error: Invalid argument").execute().expectExitCode(0); } @Override diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/ScriptSpec.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/ScriptSpec.java index 60e5723e9a71..e51efb57825e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/ScriptSpec.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/ScriptSpec.java @@ -165,10 +165,6 @@ public Builder add(CommandMockSpec mockSpec) { return build(mockSpec).add(); } - public Builder addLoop(CommandMockSpec mockSpec) { - return build(mockSpec).add(); - } - public ItemBuilder build(CommandMockSpec mockSpec) { return new ItemBuilder(mockSpec); } diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxDebPackagerTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxDebPackagerTest.java new file mode 100644 index 000000000000..e375ea66e8ce --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxDebPackagerTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException; +import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedResultException; +import jdk.jpackage.internal.util.Result; +import jdk.jpackage.internal.util.RetryExecutor; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.CommandMockSpec; +import jdk.jpackage.test.mock.ScriptSpec; +import jdk.jpackage.test.stdmock.JPackageMockUtils; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class LinuxDebPackagerTest { + + /** + * Exercise {@link LinuxDebPackager#buildPackage()}. + */ + @ParameterizedTest + @MethodSource + void test_buildPackage(TestSpec testSpec, @TempDir Path workDir) { + testSpec.run(workDir); + } + + record TestSpec(ScriptSpec scriptSpec, Optional> expectedErrorType) { + + TestSpec { + Objects.requireNonNull(scriptSpec); + Objects.requireNonNull(expectedErrorType); + } + + TestSpec(ScriptSpec scriptSpec) { + this(scriptSpec, Optional.empty()); + } + + TestSpec(ScriptSpec scriptSpec, Class expectedErrorType) { + this(scriptSpec, Optional.of(expectedErrorType)); + } + + void run(Path workDir) { + + var script = scriptSpec.create(); + + ExecutorFactory executorFactory = JPackageMockUtils.buildJPackage() + .script(script).listener(System.out::println).createExecutorFactory(); + + var objectFactory = ObjectFactory.build() + .executorFactory(executorFactory) + .retryExecutorFactory(new RetryExecutorFactory() { + @Override + public RetryExecutor retryExecutor(Class exceptionType) { + return RetryExecutorFactory.DEFAULT.retryExecutor(exceptionType).setSleepFunction(_ -> { + // Don't "sleep" to make the test run faster. + }); + } + }) + .create(); + + Globals.main(() -> { + Globals.instance().objectFactory(objectFactory); + + expectedErrorType.ifPresentOrElse(v -> { + var ex = assertThrows(Exception.class, () -> { + runPackagingMock(workDir); + }); + + var cause = ExceptionBox.unbox(ex); + + assertEquals(v, cause.getClass()); + }, () -> { + assertDoesNotThrow(() -> { + runPackagingMock(workDir); + }); + }); + + return 0; + }); + + assertEquals(List.of(), script.incompleteMocks()); + } + } + + private static Collection test_buildPackage() { + + Collection testCases = new ArrayList<>(); + + testCases.add(new TestSpec( + ScriptSpec.build() + .build(new CommandMockSpec("fakeroot", CommandActionSpecs.build().exit().create())) + .detailedDescription().add() + .create())); + + testCases.add(new TestSpec( + ScriptSpec.build() + .build(new CommandMockSpec("fakeroot", CommandActionSpecs.build().exit(1).create())) + .detailedDescription().add() + .create(), + UnexpectedExitCodeException.class)); + + testCases.add(new TestSpec( + ScriptSpec.build() + .build(new CommandMockSpec("fakeroot", CommandActionSpecs.build() + .stderr("semop(1): encountered an error: Invalid argument") + .exit(1).create())) + .repeat(4).detailedDescription().add() + .create(), + UnexpectedResultException.class)); + + testCases.add(new TestSpec( + ScriptSpec.build() + .build(new CommandMockSpec("fakeroot", CommandActionSpecs.build() + .stderr("semop(1): encountered an error: Invalid argument") + .exit(1).create())) + .repeat(3).detailedDescription().add() + .build(new CommandMockSpec("fakeroot", CommandActionSpecs.build().exit().create())) + .detailedDescription().add() + .create())); + + return testCases; + } + + private static LinuxDebSystemEnvironment dummySysEnv() { + + var linuxSysEnv = new LinuxSystemEnvironment.Stub(false, LINUX_DEB, new LinuxPackageArch("acme"), _ -> { + throw new AssertionError(); + }); + var debMixin = new LinuxDebSystemEnvironmentMixin.Stub(Path.of("dpkg"), Path.of("dpkg-deb"), Path.of("fakeroot")); + + return LinuxSystemEnvironment.mixin( + LinuxDebSystemEnvironment.class, + Result.ofValue(linuxSysEnv), + () -> Result.ofValue(debMixin)).orElseThrow(); + } + + private static void runPackagingMock(Path workDir) { + + var app = new ApplicationBuilder() + .appImageLayout(RuntimeLayout.DEFAULT) + .name("foo").create(); + + var sysEnv = dummySysEnv(); + + var pkg = new LinuxDebPackageBuilder( + new LinuxPackageBuilder(new PackageBuilder(app, LINUX_DEB)) + .arch(sysEnv.packageArch()) + ).create(); + + var buildEnv = new BuildEnvBuilder(workDir.resolve("build-root")).appImageDirFor(pkg).create(); + + var packager = new LinuxDebPackager(buildEnv, pkg, workDir, dummySysEnv()); + + var pipelineBuilder = LinuxPackagingPipeline.build(Optional.of(pkg)); + packager.accept(pipelineBuilder); + + // Disable actions of tasks we don't care about. + pipelineBuilder.configuredTasks().filter(taskBuilder -> { + return (taskBuilder.task() != PackageTaskID.CREATE_PACKAGE_FILE); + }).forEach(taskBuilder -> { + taskBuilder.noaction().add(); + }); + + pipelineBuilder.create().execute(buildEnv, pkg, workDir); + } +} diff --git a/test/jdk/tools/jpackage/junit/linux/junit.java b/test/jdk/tools/jpackage/junit/linux/junit.java index 51409f2b3d1c..8ff41471b311 100644 --- a/test/jdk/tools/jpackage/junit/linux/junit.java +++ b/test/jdk/tools/jpackage/junit/linux/junit.java @@ -88,3 +88,14 @@ * jdk/jpackage/internal/DesktopEntryFileValidatorTest.java * @run junit jdk.jpackage/jdk.jpackage.internal.DesktopEntryFileValidatorTest */ + +/* @test + * @summary Test LinuxDebPackager + * @requires (os.family == "linux") + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.mock.* + * @build jdk.jpackage.test.stdmock.* + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/LinuxDebPackagerTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.LinuxDebPackagerTest + */ From b6bd0671ce59b7fe7850e467f268997878792b6b Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 1 Sep 2026 01:48:44 +0000 Subject: [PATCH 161/223] 8391509: Add serviceability/jvmti/RedefineClasses/RedefineRunningMethodsWithBacktrace.java to the ProblemList for Windows-x64 Reviewed-by: jpai --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 59bbb43c379b..a88536fb005d 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -137,6 +137,8 @@ serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStr serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java 8385679 generic-all +serviceability/jvmti/RedefineClasses/RedefineRunningMethodsWithBacktrace.java 8390812 windows-x64 + ############################################################################# # :hotspot_misc From 60f14fb260103d1be756f7ad6f959f377a89b08f Mon Sep 17 00:00:00 2001 From: Lijuan Li Date: Tue, 1 Sep 2026 02:50:38 +0000 Subject: [PATCH 162/223] 8353495: tools/launcher/ExecutionEnvironment.java fails on RISC-V when run by qemu Reviewed-by: alanb, fyang, dzhang --- test/jdk/tools/launcher/ExecutionEnvironment.java | 3 ++- test/jdk/tools/launcher/Test7029048.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/launcher/ExecutionEnvironment.java b/test/jdk/tools/launcher/ExecutionEnvironment.java index dbf20fc5bb9c..793ac6896b96 100644 --- a/test/jdk/tools/launcher/ExecutionEnvironment.java +++ b/test/jdk/tools/launcher/ExecutionEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ * @bug 4780570 4731671 6354700 6367077 6670965 4882974 * @summary Checks for LD_LIBRARY_PATH and execution on *nixes * @requires os.family != "windows" + * @requires os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*") * @library /test/lib * @modules jdk.compiler * jdk.zipfs diff --git a/test/jdk/tools/launcher/Test7029048.java b/test/jdk/tools/launcher/Test7029048.java index f92867044a16..fa0c4f871b40 100644 --- a/test/jdk/tools/launcher/Test7029048.java +++ b/test/jdk/tools/launcher/Test7029048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @summary Ensure that the launcher defends against user settings of the * LD_LIBRARY_PATH environment variable on Unixes * @requires os.family != "windows" & os.family != "mac" + * @requires os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*") * @library /test/lib * @compile ExecutionEnvironment.java Test7029048.java * @run main/othervm Test7029048 From 5c73977e65ab879e01244acd96bca0fecddffc41 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 1 Sep 2026 03:26:48 +0000 Subject: [PATCH 163/223] 8391439: C2: Add StressVerifyMeetJoin option Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/c2_globals.hpp | 3 + src/hotspot/share/opto/compile.cpp | 7 ++ src/hotspot/share/opto/type.cpp | 80 ++++++++++++++++++- src/hotspot/share/opto/type.hpp | 2 + .../compiler/arguments/TestStressOptions.java | 6 +- 5 files changed, 92 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 6a3ef6f2dc90..76639a5ef817 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -70,6 +70,9 @@ develop(bool, StressBailout, false, \ "Perform bailouts randomly at C2 failing() checks") \ \ + develop(bool, StressVerifyMeetJoin, false, \ + "Perform cross meet/join sanity checks on all Type instances") \ + \ product(bool, OptimizeReachabilityFences, true, DIAGNOSTIC, \ "Optimize reachability fences " \ "(leave reachability fence nodes intact when turned off)") \ diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index fbecaba01a50..0a02854e8ba1 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -50,6 +50,7 @@ #include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/block.hpp" +#include "opto/c2_globals.hpp" #include "opto/c2compiler.hpp" #include "opto/callGenerator.hpp" #include "opto/callnode.hpp" @@ -944,6 +945,12 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, // Now generate code Code_Gen(); + +#ifdef ASSERT + if (StressVerifyMeetJoin) { + Type::verify_meet_join(); + } +#endif // ASSERT } // C2 uses runtime stubs serialized generation to initialize its static tables diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 532ccc929964..7e0ea7d294c3 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -1537,6 +1537,78 @@ void Type::typerr( const Type *t ) const { ShouldNotReachHere(); } +#ifdef ASSERT +void Type::verify_meet_join() { + auto should_check = [](const Type* t1, const Type* t2) { + if (t1->base() > t2->base()) { + swap(t1, t2); + } + + switch (t1->base()) { + case Bottom: + case Top: + return true; + case Array: + case Interfaces: + case Tuple: + case Function: + return false; + case DoubleBot: + case DoubleCon: + case DoubleTop: + return t2->isa_double() != nullptr; + case FloatBot: + case FloatCon: + case FloatTop: + return t2->isa_float() != nullptr; + case HalfFloatBot: + case HalfFloatCon: + case HalfFloatTop: + return t2->isa_half_float() != nullptr; + case AnyPtr: + return t2->isa_ptr() != nullptr; + case OopPtr: + case InstPtr: + return t2->isa_oopptr() != nullptr; + case AryPtr: + // When UseCompressedOops is false, not all AryPtr instances agree on whether their elems + // are compressed (e.g. TypeAryPtr::NARROWOOPS and TypeAryPtr::OOPS) + return t2->isa_oopptr() != nullptr && UseCompressedOops; + case InstKlassPtr: + case AryKlassPtr: + return t2->isa_klassptr() != nullptr; + case VectorA: + case VectorS: + case VectorD: + case VectorX: + case VectorY: + case VectorZ: + case VectorMask: + return t1 == t2; + default: + return t1->base() == t2->base(); + } + }; + + ResourceMark rm; + const Dict* all_types = type_dict(); + GrowableArray all_types_snapshot(all_types->Size()); + for (DictI iter(all_types); iter.test(); ++iter) { + all_types_snapshot.append(static_cast(iter._key)); + } + + for (int i = 0; i < all_types_snapshot.length(); i++) { + const Type* t1 = all_types_snapshot.at(i); + for (int j = i; j < all_types_snapshot.length(); j++) { + const Type* t2 = all_types_snapshot.at(j); + if (should_check(t1, t2)) { + // This will invoke Type::check_fundamental_laws + t1->meet(t2); + } + } + } +} +#endif // ASSERT //============================================================================= // Convenience common pre-built types. @@ -4974,7 +5046,7 @@ const Type* TypeAryPtr::xmeet_helper(const Type* t) const { int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case TopPTR: - return this; + return make(ptr, const_oop(), ary(), klass(), klass_is_exact(), offset, field_offset(), instance_id(), speculative, depth, is_autobox_cache()); case BotPTR: case NotNull: return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); @@ -5787,7 +5859,7 @@ const Type* TypeInstKlassPtr::xmeet(const Type* t) const { PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case TopPTR: - return this; + return make(ptr, instance_klass(), interfaces(), offset, flat_in_array()); case Null: if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case AnyNull: @@ -5823,7 +5895,7 @@ const Type* TypeInstKlassPtr::xjoin(const Type* t) const { return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case NotNull: case BotPTR: - return make(ptr, klass(), interfaces(), offset); + return make(ptr, klass(), interfaces(), offset, flat_in_array()); default: typerr(t); } @@ -6276,7 +6348,7 @@ const Type* TypeAryKlassPtr::xmeet(const Type* t) const { PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case TopPTR: - return this; + return make(ptr, elem(), klass(), offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type()); case Null: if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case AnyNull: diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 40eacfb9b182..aa25d0cc9eac 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -423,6 +423,8 @@ class Type { #endif // !PRODUCT [[noreturn]] void typerr(const Type *t) const; // Mixing types error + DEBUG_ONLY(static void verify_meet_join()); + // Create basic type static const Type* get_const_basic_type(BasicType type) { assert((uint)type <= T_CONFLICT && _const_basic_type[type] != nullptr, "bad type"); diff --git a/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java b/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java index 99cf06110d67..068a72914771 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java +++ b/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @key stress randomness - * @bug 8252219 8256535 8317349 8319879 8335334 8325478 8387940 + * @bug 8252219 8256535 8317349 8319879 8335334 8325478 8387940 8391439 * @requires vm.compiler2.enabled * @summary Tests that different combinations of stress options and * -XX:StressSeed=N are accepted. @@ -64,6 +64,8 @@ * compiler.arguments.TestStressOptions * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressEliminateAllocations -XX:StressSeed=42 * compiler.arguments.TestStressOptions + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+StressVerifyMeetJoin + * ${test.main.class} */ package compiler.arguments; From e6d577af53ed35020474c173bb2aa9c8e2551c09 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 1 Sep 2026 05:56:50 +0000 Subject: [PATCH 164/223] 8391299: Shenandoah: Improve GC trigger messages Reviewed-by: wkemper, ruili --- .../shenandoahAdaptiveHeuristics.cpp | 34 ++++++++++--------- .../shenandoahCompactHeuristics.cpp | 6 ++-- .../heuristics/shenandoahHeuristics.cpp | 8 ++--- .../heuristics/shenandoahOldHeuristics.cpp | 15 ++++---- .../heuristics/shenandoahStaticHeuristics.cpp | 6 ++-- .../heuristics/shenandoahYoungHeuristics.cpp | 4 +-- .../gc/shenandoah/shenandoahControlThread.cpp | 2 +- .../shenandoahGenerationalControlThread.cpp | 2 +- .../jtreg/gc/shenandoah/TestPeriodicGC.java | 12 +++---- .../generational/TestOldGrowthTriggers.java | 2 +- 10 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index dd259497d341..55a582cd54c2 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -228,7 +228,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { PROPERFMTARGS(available), PROPERFMTARGS(capacity)); if (_start_gc_is_pending) { - log_trigger("GC start is already pending"); + log_info(gc, ergo)("GC start is already pending"); return true; } @@ -263,7 +263,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { bool ShenandoahAdaptiveHeuristics::trigger_min_free_threshold(size_t available, size_t capacity) { const size_t min_threshold = min_free_threshold(capacity); if (available < min_threshold) { - log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", + log_trigger("Occupancy. " PROPERFMT " free, below " PROPERFMT " threshold", PROPERFMTARGS(available), PROPERFMTARGS(min_threshold)); accept_trigger_with_type(OTHER); return true; @@ -276,8 +276,9 @@ bool ShenandoahAdaptiveHeuristics::trigger_learning(size_t available, size_t cap if (_gc_times_learned < ShenandoahLearningSteps) { const size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold; if (available < init_threshold) { - log_trigger("Learning %zu of %zu. Free (" PROPERFMT ") is below initial threshold (" PROPERFMT ")", - _gc_times_learned + 1, ShenandoahLearningSteps, PROPERFMTARGS(available), PROPERFMTARGS(init_threshold)); + log_trigger("Learning. Step %zu of %zu, " PROPERFMT " free, below " PROPERFMT " threshold", + _gc_times_learned + 1, ShenandoahLearningSteps, + PROPERFMTARGS(available), PROPERFMTARGS(init_threshold)); accept_trigger_with_type(OTHER); return true; } @@ -287,10 +288,11 @@ bool ShenandoahAdaptiveHeuristics::trigger_learning(size_t available, size_t cap bool ShenandoahAdaptiveHeuristics::trigger_average_allocation_rate(const ShenandoahAnticipatedConsumption& rate, const size_t allocatable_bytes) { if (rate.baseline_consumption() > allocatable_bytes) { - log_trigger("Anticipated GC duration (%.2f ms) is above the time for average allocation rate (" PROPERFMT_F "/s)" - " to deplete free headroom (" PROPERFMT ") (margin of error = %.2f)", - rate.duration_seconds() * 1000, - PROPERFMT_F_ARGS(rate.baseline_rate()), PROPERFMTARGS(allocatable_bytes), _margin_of_error_sd); + const ShenandoahSignedSize baseline_rate = ShenandoahSignedSize::get(rate.baseline_rate()); + log_trigger("Allocation Rate. %.2fms GC predicted, " PROPERFMT " free, " + PROPERFMT_F "/s average allocation rate", + rate.duration_seconds() * 1000, PROPERFMTARGS(allocatable_bytes), + PROPERFMTARGS_SIGNED(baseline_rate)); accept_trigger_with_type(RATE); return true; } @@ -383,10 +385,10 @@ bool ShenandoahAdaptiveHeuristics::trigger_accelerating_allocation_rate(const Sh if (rate.momentary_consumption() > allocatable_bytes) { const ShenandoahSignedSize momentary_rate = ShenandoahSignedSize::get(rate.momentary_rate()); assert(rate.accelerated_consumption() == 0, "Momentary trigger is meant to exclude acceleration trigger"); - log_trigger("Momentary spike consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " - "current rate (" PROPERFMT_F "/s) for anticipated GC duration (%.2f ms)", - PROPERFMTARGS(rate.momentary_consumption()), PROPERFMTARGS(allocatable_bytes), - PROPERFMTARGS_SIGNED(momentary_rate), rate.duration_seconds() * 1000); + log_trigger("Allocation Rate. %.2fms GC predicted, " PROPERFMT " free, " + PROPERFMT_F "/s momentary allocation rate", + rate.duration_seconds() * 1000, PROPERFMTARGS(allocatable_bytes), + PROPERFMTARGS_SIGNED(momentary_rate)); accept_trigger_with_type(RATE); return true; } @@ -395,10 +397,10 @@ bool ShenandoahAdaptiveHeuristics::trigger_accelerating_allocation_rate(const Sh const ShenandoahSignedSize predicted_rate = ShenandoahSignedSize::get(rate.predicted_rate()); const ShenandoahSignedSize acceleration = ShenandoahSignedSize::get(rate.acceleration()); assert(rate.momentary_consumption() == 0, "Acceleration trigger is meant to exclude momentary trigger"); - log_trigger("Accelerated consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " - "current rate (" PROPERFMT_F "/s) with acceleration (" PROPERFMT_F "/s/s) for anticipated GC duration (%.2f ms)", - PROPERFMTARGS(rate.accelerated_consumption()), PROPERFMTARGS(allocatable_bytes), - PROPERFMTARGS_SIGNED(predicted_rate), PROPERFMTARGS_SIGNED(acceleration), rate.duration_seconds() * 1000); + log_trigger("Allocation Rate. %.2fms GC predicted, " PROPERFMT " free, " + PROPERFMT_F "/s predicted allocation rate, " PROPERFMT_F "/s^2 acceleration", + rate.duration_seconds() * 1000, PROPERFMTARGS(allocatable_bytes), + PROPERFMTARGS_SIGNED(predicted_rate), PROPERFMTARGS_SIGNED(acceleration)); accept_trigger_with_type(RATE); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index 26a2363d4d50..a11820e5a809 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,14 +60,14 @@ bool ShenandoahCompactHeuristics::should_start_gc() { const size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; if (available < min_threshold) { - log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", + log_trigger("Occupancy. " PROPERFMT " free, below " PROPERFMT " threshold", PROPERFMTARGS(available), PROPERFMTARGS(min_threshold)); accept_trigger(); return true; } if (bytes_allocated > threshold_bytes_allocated) { - log_trigger("Allocated since last cycle started (" PROPERFMT ") is larger than allocation threshold (" PROPERFMT ")", + log_trigger("Allocation. " PROPERFMT " allocated, above " PROPERFMT " threshold", PROPERFMTARGS(bytes_allocated), PROPERFMTARGS(threshold_bytes_allocated)); accept_trigger(); return true; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index a0aec3c70a29..410514a3a02d 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2018, 2026, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,7 +189,7 @@ void ShenandoahHeuristics::record_cycle_end() { bool ShenandoahHeuristics::should_start_gc() { if (_start_gc_is_pending) { - log_trigger("GC start is already pending"); + log_info(gc, ergo)("GC start is already pending"); return true; } // Perform GC to cleanup metaspace @@ -203,8 +203,8 @@ bool ShenandoahHeuristics::should_start_gc() { if (_guaranteed_gc_interval > 0) { double last_time_ms = (os::elapsedTime() - _last_cycle_end) * 1000; if (last_time_ms > _guaranteed_gc_interval) { - log_trigger("Time since last GC (%.0f ms) is larger than guaranteed interval (%zu ms)", - last_time_ms, _guaranteed_gc_interval); + log_trigger("Guaranteed Interval. %.0f ms since last GC, above %zu ms guaranteed interval", + last_time_ms, _guaranteed_gc_interval); accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 44bc683cbd6c..8d44b2878b6f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -724,13 +724,13 @@ bool ShenandoahOldHeuristics::should_resume_old_cycle() { // If we are preparing to mark old, or if we are already marking old, then try to continue that work. if (_old_generation->is_concurrent_mark_in_progress()) { assert(_old_generation->state() == ShenandoahOldGeneration::MARKING, "Unexpected old gen state: %s", _old_generation->state_name()); - log_trigger("Resume marking old"); + log_trigger("Resume Marking"); return true; } if (_old_generation->is_preparing_for_mark()) { assert(_old_generation->state() == ShenandoahOldGeneration::FILLING, "Unexpected old gen state: %s", _old_generation->state_name()); - log_trigger("Resume preparing to mark old"); + log_trigger("Resume Prepare Marking"); return true; } @@ -750,7 +750,7 @@ bool ShenandoahOldHeuristics::should_start_gc() { const size_t old_gen_capacity = _old_generation->max_capacity(); const size_t heap_capacity = heap->capacity(); const double percent = percent_of(old_gen_capacity, heap_capacity); - log_trigger("Expansion failure, current size: %zu%s which is %.1f%% of total heap size", + log_trigger("Handle Expansion Failure. %zu%s (%.1f%%) old generation", byte_size_in_proper_unit(old_gen_capacity), proper_unit_for_byte_size(old_gen_capacity), percent); adjust_old_garbage_threshold(); return true; @@ -770,9 +770,7 @@ bool ShenandoahOldHeuristics::should_start_gc() { const size_t span_of_old_regions = (last_old_region >= first_old_region)? last_old_region + 1 - first_old_region: 0; const size_t fragmented_free = used_regions_size - used; - log_trigger("Old has become fragmented: " - "%zu%s available bytes spread between range spanned from " - "%zu to %zu (%zu), density: %.1f%%", + log_trigger("Fragmentation. %zu%s available in old, [%zu, %zu] (%zu) regions, density: %.1f%%", byte_size_in_proper_unit(fragmented_free), proper_unit_for_byte_size(fragmented_free), first_old_region, last_old_region, span_of_old_regions, density * 100); adjust_old_garbage_threshold(); @@ -800,8 +798,7 @@ bool ShenandoahOldHeuristics::should_start_gc() { } else if (current_usage > trigger_threshold) { const size_t live_at_previous_old = _old_generation->get_live_bytes_at_last_mark(); const double percent_growth = percent_of(current_usage - live_at_previous_old, live_at_previous_old); - log_trigger("Old has overgrown, live at end of previous OLD marking: " - "%zu%s, current usage: %zu%s, percent growth: %.1f%%", + log_trigger("Occupancy. %zu%s live at old mark end, %zu%s used, %.1f%% growth", byte_size_in_proper_unit(live_at_previous_old), proper_unit_for_byte_size(live_at_previous_old), byte_size_in_proper_unit(current_usage), proper_unit_for_byte_size(current_usage), percent_growth); adjust_old_garbage_threshold(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp index 98d679f86d9c..0ceab0460cfd 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,8 +46,8 @@ bool ShenandoahStaticHeuristics::should_start_gc() { size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold; if (available < threshold_available) { - log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", - PROPERFMTARGS(available), PROPERFMTARGS(threshold_available)); + log_trigger("Occupancy. " PROPERFMT " free, below " PROPERFMT " threshold", + PROPERFMTARGS(available), PROPERFMTARGS(threshold_available)); accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index 280076377594..49be36aaf949 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -138,7 +138,7 @@ bool ShenandoahYoungHeuristics::trigger_expedite_promotions(ShenandoahGeneration if (promo_potential > promo_expedite_threshold) { // Detect unsigned arithmetic underflow assert(promo_potential < heap->capacity(), "Sanity"); - log_trigger("Expedite promotion of " PROPERFMT, PROPERFMTARGS(promo_potential)); + log_trigger("Expedite Promotion. " PROPERFMT " promotion potential", PROPERFMTARGS(promo_potential)); accept_trigger(); return true; } @@ -152,7 +152,7 @@ bool ShenandoahYoungHeuristics::trigger_expedite_mixed(ShenandoahGenerationalHea // If concurrent weak root processing is in progress, it means the old cycle has chosen mixed collection // candidates, but has not completed. There is no point in trying to start the young cycle before the old // cycle completes. - log_trigger("Expedite mixed evacuation of %zu regions", mixed_candidates); + log_trigger("Expedite Mixed. %zu region candidates for mixed evacuation", mixed_candidates); accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 4006b443d14f..a76c81a4f06d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -97,7 +97,7 @@ void ShenandoahControlThread::run_service() { } } else if (is_gc_requested) { cause = requested_gc_cause; - heuristics->log_trigger("GC request (%s)", GCCause::to_string(cause)); + heuristics->log_trigger("%s", GCCause::to_string(cause)); heuristics->record_requested_gc(); if (ShenandoahCollectorPolicy::should_run_full_gc(cause)) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index e5405e1283c2..68ac2cdb1c7b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -184,7 +184,7 @@ ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread: ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_explicit_gc(ShenandoahGCRequest &request) const { ShenandoahHeuristics* global_heuristics = _heap->global_generation()->heuristics(); request.generation = _heap->global_generation(); - global_heuristics->log_trigger("GC request (%s)", GCCause::to_string(request.cause)); + global_heuristics->log_trigger("%s", GCCause::to_string(request.cause)); global_heuristics->record_requested_gc(); if (ShenandoahCollectorPolicy::should_run_full_gc(request.cause)) { diff --git a/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java b/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java index 58f102298ff4..edafded07dc5 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestPeriodicGC.java @@ -47,10 +47,10 @@ public static void testWith(String msg, boolean periodic, String... args) throws output.shouldHaveExitValue(0); if (periodic) { - output.shouldContain("Trigger: Time since last GC"); + output.shouldContain("Trigger: Guaranteed Interval."); } if (!periodic) { - output.shouldNotContain("Trigger: Time since last GC"); + output.shouldNotContain("Trigger: Guaranteed Interval."); } } @@ -63,11 +63,11 @@ public static void testGenerational(boolean periodic, String... args) throws Exc OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); if (periodic) { - output.shouldContain("Trigger (Young): Time since last GC"); - output.shouldContain("Trigger (Old): Time since last GC"); + output.shouldContain("Trigger (Young): Guaranteed Interval."); + output.shouldContain("Trigger (Old): Guaranteed Interval."); } else { - output.shouldNotContain("Trigger (Young): Time since last GC"); - output.shouldNotContain("Trigger (Old): Time since last GC"); + output.shouldNotContain("Trigger (Young): Guaranteed Interval."); + output.shouldNotContain("Trigger (Old): Guaranteed Interval."); } } diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java index fe3c8a5a4763..7fd78e874c9c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java @@ -91,7 +91,7 @@ public static void testOld(String... args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); - output.shouldContain("Trigger (Old): Old has overgrown"); + output.shouldContain("Trigger (Old): Occupancy."); } public static void main(String[] args) throws Exception { From 0b44562c17ef0851ae45d1268b934bb9af428895 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 1 Sep 2026 06:56:59 +0000 Subject: [PATCH 165/223] 8391518: Un-ProblemList runtime/Thread/TestAlwaysPreTouchStacks.java on macOS Reviewed-by: jsjolen --- test/hotspot/jtreg/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a88536fb005d..89995c8e9658 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -102,7 +102,6 @@ runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/NMT/VirtualAllocCommitMerge.java 8309698 linux-s390x -runtime/Thread/TestAlwaysPreTouchStacks.java 8383372 macosx-aarch64 applications/jcstress/copy.java 8229852 linux-all From 2ddafbb7fda73cd6cc42cf3ec8d8e51c6400c735 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 1 Sep 2026 07:30:53 +0000 Subject: [PATCH 166/223] 8391351: G1: G1HeapRegionRemSet double counts code roots in mem_size() Reviewed-by: aivy, ayang --- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index b185aa3151c2..3fc943a29516 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -162,7 +162,7 @@ class G1HeapRegionRemSet : public CHeapObj { // The actual # of bytes this hr_remset takes up. Also includes the code // root set. size_t mem_size() { - return sizeof(G1HeapRegionRemSet) + code_roots_mem_size(); + return sizeof(G1HeapRegionRemSet) - sizeof(G1CodeRootSet) + code_roots_mem_size(); } // Returns the memory occupancy of all static data structures associated From 66c7cac0ad8787e7528f2d33e71724004d20999b Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 1 Sep 2026 07:43:39 +0000 Subject: [PATCH 167/223] 8391186: Avoid unused variables in libjsound Reviewed-by: azvegint, prr --- make/modules/java.desktop/Lib.gmk | 6 ++--- .../PLATFORM_API_LinuxOS_ALSA_MidiOut.c | 4 +-- .../libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c | 6 ++--- .../PLATFORM_API_LinuxOS_ALSA_Ports.c | 3 +-- .../libjsound/PLATFORM_API_MacOSX_MidiUtils.c | 26 ++++++++++++++----- .../libjsound/PLATFORM_API_MacOSX_PCM.cpp | 10 +++++-- .../libjsound/PLATFORM_API_MacOSX_Utils.cpp | 2 -- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/make/modules/java.desktop/Lib.gmk b/make/modules/java.desktop/Lib.gmk index 1c43950480c4..9d2a82d60321 100644 --- a/make/modules/java.desktop/Lib.gmk +++ b/make/modules/java.desktop/Lib.gmk @@ -64,10 +64,8 @@ ifeq ($(ENABLE_JSOUND), true) EXTRA_HEADER_DIRS := java.base:libjava, \ CFLAGS := $(LIBJSOUND_CFLAGS), \ CXXFLAGS := $(LIBJSOUND_CFLAGS), \ - DISABLED_WARNINGS_gcc := undef unused-variable, \ - DISABLED_WARNINGS_clang := undef unused-variable, \ - DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_MidiUtils.c := \ - unused-but-set-variable, \ + DISABLED_WARNINGS_gcc := undef, \ + DISABLED_WARNINGS_clang := undef, \ DISABLED_WARNINGS_clang_DirectAudioDevice.c := unused-function, \ LIBS_linux := $(ALSA_LIBS), \ LIBS_macosx := \ diff --git a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c index 37d8d943a9aa..a4dfea1d1bc3 100644 --- a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,8 +120,6 @@ INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) { int err; int status; - int data1; - int data2; char buffer[3]; TRACE2("> MIDI_OUT_SendShortMessage() %x, time: %u\n", packedMsg, (unsigned int) timestamp); diff --git a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c index 332abb58b6fb..d77c30840c42 100644 --- a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_PCM.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -412,13 +412,14 @@ int setSWParams(AlsaPcmInfo* info) { return TRUE; } +#ifdef USE_TRACE static snd_output_t* ALSA_OUTPUT = NULL; +#endif void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, int encoding, float sampleRate, int sampleSizeInBits, int frameSize, int channels, int isSigned, int isBigEndian, int bufferSizeInBytes) { - snd_pcm_format_mask_t* formatMask; snd_pcm_format_t format; int dir; int ret = 0; @@ -888,7 +889,6 @@ INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { if (!info->isFlushed && state != SND_PCM_STATE_XRUN) { #ifdef GET_POSITION_METHOD2 - snd_timestamp_t* ts; snd_pcm_uframes_t framesAvail; // note: slight race condition if this is called simultaneously from 2 threads diff --git a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c index c57b2bd3cf50..f14742cb3977 100644 --- a/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c +++ b/src/java.desktop/linux/native/libjsound/PLATFORM_API_LinuxOS_ALSA_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -532,7 +532,6 @@ INT32 PORT_GetIntValue(void* controlIDV) { void PORT_SetIntValue(void* controlIDV, INT32 value) { PortControl* portControl = (PortControl*) controlIDV; - snd_mixer_selem_channel_id_t channel; if (portControl != NULL) { if (portControl->controlType == CONTROL_TYPE_MUTE) { diff --git a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_MidiUtils.c b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_MidiUtils.c index 09aeb863496b..00b450bd9871 100644 --- a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_MidiUtils.c +++ b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_MidiUtils.c @@ -542,8 +542,9 @@ INT32 MIDI_Utils_CloseDevice(MacMidiDeviceHandle* handle) { INT32 MIDI_Utils_StartDevice(MacMidiDeviceHandle* handle) { +#ifdef USE_ERROR OSStatus err = noErr; - +#endif if (!handle || !handle->h.deviceHandle) { ERROR0("ERROR: MIDI_Utils_StartDevice: handle or native is NULL\n"); return MIDI_INVALID_HANDLE; @@ -565,10 +566,16 @@ INT32 MIDI_Utils_StartDevice(MacMidiDeviceHandle* handle) { // Similarly, handle->h.queue is used in the CoreMDID's callback // to dispatch the incoming messages to the appropriate queue. // - err = MIDIPortConnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle), (void*) handle); +#ifdef USE_ERROR + err = +#endif + MIDIPortConnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle), (void*) handle); } else if (handle->direction == MIDI_OUT) { // Unschedules previous-sent packets. - err = MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); +#ifdef USE_ERROR + err = +#endif + MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); } MIDI_CHECK_ERROR; @@ -578,8 +585,9 @@ INT32 MIDI_Utils_StartDevice(MacMidiDeviceHandle* handle) { INT32 MIDI_Utils_StopDevice(MacMidiDeviceHandle* handle) { +#ifdef USE_ERROR OSStatus err = noErr; - +#endif if (!handle || !handle->h.deviceHandle) { ERROR0("ERROR: MIDI_Utils_StopDevice: handle or native handle is NULL\n"); return MIDI_INVALID_HANDLE; @@ -590,10 +598,16 @@ INT32 MIDI_Utils_StopDevice(MacMidiDeviceHandle* handle) { handle->isStarted = FALSE; if (handle->direction == MIDI_IN) { - err = MIDIPortDisconnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle)); +#ifdef USE_ERROR + err = +#endif + MIDIPortDisconnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle)); } else if (handle->direction == MIDI_OUT) { // Unschedules previously-sent packets. - err = MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); +#ifdef USE_ERROR + err = +#endif + MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); } MIDI_CHECK_ERROR; diff --git a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp index bae16cb0a9c0..5364978a257c 100644 --- a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp +++ b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_PCM.cpp @@ -764,10 +764,16 @@ static OSStatus InputCallback(void *inRefCon, } device->lastWrittenSampleTime = sampleTime + inNumberFrames; - int bytesWritten = device->resampler->Process(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, &device->ringBuffer); +#ifdef USE_TRACE + int bytesWritten = +#endif + device->resampler->Process(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, &device->ringBuffer); TRACE2("<ringBuffer.Write(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, false); +#ifdef USE_TRACE + int bytesWritten = +#endif + device->ringBuffer.Write(abl.mBuffers[0].mData, (int)abl.mBuffers[0].mDataByteSize, false); TRACE2("< Date: Tue, 1 Sep 2026 08:10:21 +0000 Subject: [PATCH 168/223] 8371327: G1: Replace FromCardCache with thread-local per-card cache Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 18 +--- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 10 -- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 4 +- .../share/gc/g1/g1CollectionSetCandidates.cpp | 35 ++++--- .../share/gc/g1/g1CollectionSetCandidates.hpp | 42 ++++----- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 6 +- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 3 - .../gc/g1/g1ConcurrentMarkRemarkTasks.cpp | 4 +- .../gc/g1/g1ConcurrentRebuildAndScrub.cpp | 17 ++-- .../gc/g1/g1ConcurrentRefineSweepTask.cpp | 15 ++- src/hotspot/share/gc/g1/g1FromCardCache.cpp | 89 ------------------ src/hotspot/share/gc/g1/g1FromCardCache.hpp | 94 ++++++------------- .../share/gc/g1/g1FromCardCache.inline.hpp | 48 ++++++++++ .../share/gc/g1/g1FullGCResetMetadataTask.cpp | 10 +- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 9 +- .../share/gc/g1/g1HeapRegionRemSet.cpp | 27 +----- .../share/gc/g1/g1HeapRegionRemSet.hpp | 29 ++---- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 15 +-- src/hotspot/share/gc/g1/g1OopClosures.hpp | 21 +++-- .../share/gc/g1/g1OopClosures.inline.hpp | 6 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 11 ++- src/hotspot/share/gc/g1/g1RemSet.hpp | 3 +- .../share/gc/g1/g1RemSetTrackingPolicy.cpp | 8 +- src/hotspot/share/gc/shared/gc_globals.hpp | 4 +- .../shenandoah/shenandoahScanRemembered.hpp | 5 +- .../gtest/gc/g1/test_g1FromCardCache.cpp | 79 ++++++++++++++++ 26 files changed, 292 insertions(+), 320 deletions(-) delete mode 100644 src/hotspot/share/gc/g1/g1FromCardCache.cpp create mode 100644 src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp create mode 100644 test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 6d713ff8e1ef..833d07cb6852 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -127,16 +127,6 @@ size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; // apply to TLAB allocation, which is not part of this interface: it // is done by clients of this interface.) -void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) { - G1HeapRegionRemSet::invalidate_from_card_cache(start_idx, num_regions); -} - -void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { - // The from card cache is not the memory that is actually committed. So we cannot - // take advantage of the zero_filled parameter. - reset_from_card_cache(start_idx, num_regions); -} - // Collects commonly used scoped objects that are related to initial setup. class G1GCMark : StackObj { ResourceMark _rm; @@ -1306,7 +1296,6 @@ G1CollectedHeap::G1CollectedHeap() : _old_set("Old Region Set", new OldRegionSetChecker()), _humongous_set("Humongous Region Set", new HumongousRegionSetChecker()), _bot(nullptr), - _listener(), _numa(G1NUMA::create()), _hrm(), _allocator(nullptr), @@ -1332,7 +1321,7 @@ G1CollectedHeap::G1CollectedHeap() : _rem_set(nullptr), _card_set_config(), _card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()), - _young_regions_cset_group(card_set_config(), &_card_set_freelist_pool, G1CSetCandidateGroup::YoungRegionId), + _young_regions_cset_group(card_set_config(), &_card_set_freelist_pool, G1CSetCandidateGroup::YoungId), _cm(nullptr), _cr(nullptr), _task_queues(nullptr), @@ -1502,7 +1491,6 @@ jint G1CollectedHeap::initialize() { heap_rs.base(), heap_rs.size(), page_size); - heap_storage->set_mapping_changed_listener(&_listener); // Create storage for the BOT, card table and the bitmap. G1RegionToSpaceMapper* bot_storage = @@ -1541,10 +1529,6 @@ jint G1CollectedHeap::initialize() { const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1; guarantee((max_num_regions() - 1) <= max_region_idx, "too many regions"); - // The G1FromCardCache reserves card with value 0 as "invalid", so the heap must not - // start within the first card. - guarantee((uintptr_t)(heap_rs.base()) >= G1CardTable::card_size(), "Java heap must not start within the first card."); - G1FromCardCache::initialize(max_num_regions()); // Also create a G1 rem set. _rem_set = new G1RemSet(this); _rem_set->initialize(max_num_regions()); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 5480b5684c41..1497c61f59dd 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -111,13 +111,6 @@ class G1STWSubjectToDiscoveryClosure : public BoolObjectClosure { bool do_object_b(oop p) override; }; -class G1RegionMappingChangedListener : public G1MappingChangedListener { - private: - void reset_from_card_cache(uint start_idx, size_t num_regions); - public: - void on_commit(uint start_idx, size_t num_regions, bool zero_filled) override; -}; - // Helper to claim contiguous sets of JavaThread for processing by multiple threads. class G1JavaThreadsListClaimer : public StackObj { ThreadsListHandle _list; @@ -223,9 +216,6 @@ class G1CollectedHeap : public CollectedHeap { // free_list_only is true, it will only rebuild the free list. void rebuild_region_sets(bool free_list_only); - // Callback for region mapping changed events. - G1RegionMappingChangedListener _listener; - // Handle G1 NUMA support. G1NUMA* _numa; diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 44c3695d296e..a64b22177205 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -218,7 +218,7 @@ void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) { assert(hr->is_young(), "invariant"); assert(_inc_build_state == CSetBuildType::Active, "Precondition"); - // Add to remembered set/cardset group. + // Add to remembered set/cset group. _g1h->policy()->remset_tracker()->update_at_allocate(hr); _g1h->young_regions_cset_group()->add(hr); @@ -609,7 +609,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) // for the regions in these groups. candidates()->remove(&remove_from_retained); - groups_to_abandon.clear(true /* uninstall_group_cardset */); + groups_to_abandon.clear(true /* uninstall_cset_group */); assert(num_optional_regions >= prev_num_optional_regions, "Sanity"); uint selected_optional_regions = num_optional_regions - prev_num_optional_regions; diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index bf3372023b11..8b4acaa81e9d 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -24,10 +24,9 @@ #include "gc/g1/g1CollectionSetCandidates.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" +#include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "utilities/growableArray.hpp" -uint G1CSetCandidateGroup::_next_group_id = G1CSetCandidateGroup::InitialId; - G1CSetCandidateGroup::G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id) : _candidates(4, mtGCCardSet), _card_set_mm(config, card_set_freelist_pool), @@ -38,10 +37,16 @@ G1CSetCandidateGroup::G1CSetCandidateGroup(G1CardSetConfiguration* config, G1Mon { } G1CSetCandidateGroup::G1CSetCandidateGroup() : - G1CSetCandidateGroup(G1CollectedHeap::heap()->card_set_config(), G1CollectedHeap::heap()->card_set_freelist_pool(), _next_group_id++) + G1CSetCandidateGroup(G1CollectedHeap::heap()->card_set_config(), G1CollectedHeap::heap()->card_set_freelist_pool(), InvalidId) { } void G1CSetCandidateGroup::add(G1HeapRegion* hr) { + precond(hr->is_young() == (_group_id == YoungId)); + + if (_candidates.is_empty() && _group_id != YoungId) { + precond(_group_id == InvalidId); + _group_id = FirstNonYoungId + hr->hrm_index(); + } G1CollectionSetCandidateInfo c(hr); _candidates.append(c); hr->install_cset_group(this); @@ -63,16 +68,23 @@ double G1CSetCandidateGroup::liveness_percent() const { return ((capacity - _reclaimable_bytes) * 100.0) / capacity; } -void G1CSetCandidateGroup::clear(bool uninstall_group_cardset) { - if (uninstall_group_cardset) { +void G1CSetCandidateGroup::clear(bool uninstall_cset_group) { + clear_card_set(); + if (uninstall_cset_group) { for (G1CollectionSetCandidateInfo ci : _candidates) { G1HeapRegion* r = ci._r; r->uninstall_cset_group(); - r->rem_set()->clear(true /* only_cardset */); + r->rem_set()->set_state_untracked(); } } - _card_set.clear(); _candidates.clear(); + if (_group_id != YoungId) { + _group_id = InvalidId; + } +} + +void G1CSetCandidateGroup::clear_card_set() { + _card_set.clear(); } double G1CSetCandidateGroup::predict_group_total_time_ms() const { @@ -141,9 +153,9 @@ G1CSetCandidateGroup* G1CSetCandidateGroupList::at(uint index) { return _groups.at(index); } -void G1CSetCandidateGroupList::clear(bool uninstall_group_cardset) { +void G1CSetCandidateGroupList::clear(bool uninstall_cset_group) { for (G1CSetCandidateGroup* gr : _groups) { - gr->clear(uninstall_group_cardset); + gr->clear(uninstall_cset_group); delete gr; } _groups.clear(); @@ -232,8 +244,8 @@ void G1CollectionSetCandidates::initialize(uint max_regions) { } void G1CollectionSetCandidates::clear() { - _retained_groups.clear(true /* uninstall_group_cardset */); - _from_marking_groups.clear(true /* uninstall_group_cardset */); + _retained_groups.clear(true /* uninstall_cset_group */); + _from_marking_groups.clear(true /* uninstall_cset_group */); for (uint i = 0; i < _max_regions; i++) { _contains_map[i] = CandidateOrigin::Invalid; } @@ -267,7 +279,6 @@ void G1CollectionSetCandidates::set_candidates_from_marking(GrowableArrayCHeapcalc_min_old_cset_length(num_candidates); - G1CSetCandidateGroup::reset_next_group_id(); G1CSetCandidateGroup* current = nullptr; current = new G1CSetCandidateGroup(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index a70f9e395b64..368022a586c1 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -73,23 +73,17 @@ class G1CSetCandidateGroup : public CHeapObj{ size_t _reclaimable_bytes; double _gc_efficiency; + // The _group_id identifies a candidate group in logging and in the + // FromCardCache. A group id must be assigned to at most one cset group + // at any time. + uint _group_id; public: - // The _group_id uniquely identifies a candidate group when printing, making it - // easier to associate regions with their assigned G1CSetCandidateGroup, if any. - // Special values for the id: - // * id 0 is reserved for regions that do not have a remembered set. - // * id 1 is reserved for the G1CollectionSetCandidate that contains all young regions. - // * other ids are handed out incrementally, starting from InitialId. - static const uint NoRemSetId = 0; - static const uint YoungRegionId = 1; - static const uint InitialId = 2; + static constexpr uint NoGroupId = 0; + static constexpr uint YoungId = NoGroupId + 1; + static constexpr uint FirstNonYoungId = YoungId + 1; + static constexpr uint InvalidId = UINT_MAX; -private: - const uint _group_id; - static uint _next_group_id; - -public: G1CSetCandidateGroup(); G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id); ~G1CSetCandidateGroup() { @@ -127,7 +121,10 @@ class G1CSetCandidateGroup : public CHeapObj{ return _card_set.occupied(); } - void clear(bool uninstall_group_cardset = false); + // Clear the group-owned card set. + void clear_card_set(); + + void clear(bool uninstall_cset_group = false); G1CSetCandidateGroupIterator begin() const { return _candidates.begin(); @@ -137,10 +134,9 @@ class G1CSetCandidateGroup : public CHeapObj{ return _candidates.end(); } - uint group_id() const { return _group_id; } - - static void reset_next_group_id() { - _next_group_id = InitialId; + uint group_id() const { + assert(_group_id != InvalidId, "group must have an assigned id"); + return _group_id; } }; @@ -154,11 +150,11 @@ class G1CSetCandidateGroupList { G1CSetCandidateGroupList(); void append(G1CSetCandidateGroup* group); - // Delete all groups from the list. The cardset cleanup for regions within the - // groups could have been done elsewhere (e.g. when adding groups to the - // collection set or to retained regions). The uninstall_group_cardset is set to + // Delete all groups from the list. The card set cleanup for regions within + // the groups could have been done elsewhere (e.g. when adding groups to the + // collection set or to retained regions). The uninstall_cset_group is set to // true if cleanup needs to happen as we clear the groups from the list. - void clear(bool uninstall_group_cardset = false); + void clear(bool uninstall_cset_group = false); G1CSetCandidateGroup* at(uint index); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 2246ffc12e7f..ccac7e01db07 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -36,7 +36,6 @@ #include "gc/g1/g1ConcurrentMarkRemarkTasks.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRebuildAndScrub.hpp" -#include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionManager.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" @@ -448,7 +447,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _finger(nullptr), // _finger set in set_non_marking_state - _worker_id_offset(G1ConcRefinementThreads), // The refinement control thread does not refine cards, so it's just the worker threads. _max_num_tasks(MAX2(ConcGCThreads, ParallelGCThreads)), _num_active_tasks(0), // _num_active_tasks set in set_non_marking_state() _tasks(nullptr), @@ -502,7 +500,7 @@ void G1ConcurrentMark::fully_initialize() { vm_shutdown_during_initialization("Could not create ConcurrentMarkThread"); } - log_debug(gc)("ConcGCThreads: %u offset %u", ConcGCThreads, _worker_id_offset); + log_debug(gc)("ConcGCThreads: %u", ConcGCThreads); log_debug(gc)("ParallelGCThreads: %u", ParallelGCThreads); _max_concurrent_workers = ConcGCThreads; @@ -3161,7 +3159,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { const char* remset_type = r->rem_set()->get_short_state_str(); uint cset_group_id = r->rem_set()->has_cset_group() ? r->rem_set()->cset_group_id() - : G1CSetCandidateGroup::NoRemSetId; + : G1CSetCandidateGroup::NoGroupId; _total_used_bytes += used_bytes; _total_capacity_bytes += capacity_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 925d250ab0ad..ca36b48de5b4 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -354,7 +354,6 @@ class G1ConcurrentMark : public CHeapObj { // always pointing to the end of the // last claimed region - uint _worker_id_offset; uint _max_num_tasks; // Maximum number of marking tasks uint _num_active_tasks; // Number of tasks currently active G1CMTask** _tasks; // Task queue array (max_worker_id length) @@ -567,8 +566,6 @@ class G1ConcurrentMark : public CHeapObj { // TARS for the given region during remembered set rebuilding. inline HeapWord* top_at_rebuild_start(G1HeapRegion* r) const; - uint worker_id_offset() const { return _worker_id_offset; } - // Fully allocates and initializes data structures for the concurrent cycle. // Methods that use concurrent cycle state such as the concurrent mark threads, // tasks, marking stack, statistics, TAMS or TARS require this initialization. diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp index a7fcc566d618..61ec542c71f0 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" +#include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "gc/g1/g1RemSetTrackingPolicy.hpp" #include "logging/log.hpp" #include "runtime/mutexLocker.hpp" @@ -208,7 +209,8 @@ void G1UpdateRegionLivenessAndSelectForRebuildTask::prune(GrowableArrayCHeap allowed_waste) { break; } - r->rem_set()->clear(true /* cardset_only */); + assert(!r->rem_set()->has_cset_group(), "must not have a cset group"); + r->rem_set()->set_state_untracked(); wasted_bytes += reclaimable; num_pruned++; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp index 5b652f096a76..cf3e07592a09 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp @@ -93,8 +93,11 @@ class G1RebuildRSAndScrubTask : public WorkerTask { reset_processed_words(); // If a yield occurs (potential young-gc pause), must recheck for // potential regions reclamation. - if (_cm->do_yield_check() && !should_rebuild_or_scrub(hr)) { - return true; + if (_cm->do_yield_check()) { + _rebuild_closure.reset_from_card_cache(); + if (!should_rebuild_or_scrub(hr)) { + return true; + } } } return _cm->has_aborted() || !should_rebuild_or_scrub(hr); @@ -245,16 +248,18 @@ class G1RebuildRSAndScrubTask : public WorkerTask { } public: - G1RebuildRSAndScrubRegionClosure(G1ConcurrentMark* cm, bool should_rebuild_remset, uint worker_id) : + G1RebuildRSAndScrubRegionClosure(G1ConcurrentMark* cm, bool should_rebuild_remset) : _cm(cm), _bitmap(_cm->mark_bitmap()), - _rebuild_closure(G1CollectedHeap::heap(), worker_id + cm->worker_id_offset()), + _rebuild_closure(G1CollectedHeap::heap()), _should_rebuild_remset(should_rebuild_remset), _processed_words(0) { } bool do_heap_region(G1HeapRegion* hr) { // Avoid stalling safepoints and stop iteration if mark cycle has been aborted. - _cm->do_yield_check(); + if (_cm->do_yield_check()) { + _rebuild_closure.reset_from_card_cache(); + } if (_cm->has_aborted()) { return true; } @@ -294,7 +299,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { SuspendibleThreadSetJoiner sts_join; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1RebuildRSAndScrubRegionClosure cl(_cm, _should_rebuild_remset, worker_id); + G1RebuildRSAndScrubRegionClosure cl(_cm, _should_rebuild_remset); g1h->heap_region_par_iterate_from_worker_offset(&cl, &_hr_claimer, worker_id); } }; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp index b0cf8353dfb8..d50c31f3da48 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,6 @@ class G1RefineRegionClosure : public G1HeapRegionClosure { G1RemSet* _rem_set; G1CardTableClaimTable* _scan_state; - uint _worker_id; - bool has_work(G1HeapRegion* r) { return _scan_state->has_unclaimed_cards(r->hrm_index()); } @@ -55,7 +53,7 @@ class G1RefineRegionClosure : public G1HeapRegionClosure { void do_dirty_card(CardValue* source_card, CardValue* dest_card) { verify_card_pair_refers_to_same_card(source_card, dest_card); - G1RemSet::RefineResult res = _rem_set->refine_card_concurrently(source_card, _worker_id); + G1RemSet::RefineResult res = _rem_set->refine_card_concurrently(source_card); // Gather statistics based on the result. switch (res) { case G1RemSet::HasRefToCSet: { @@ -94,11 +92,10 @@ class G1RefineRegionClosure : public G1HeapRegionClosure { bool _completed; G1LocalRefineStats _per_worker_refine_data; - G1RefineRegionClosure(uint worker_id, G1CardTableClaimTable* scan_state) : + G1RefineRegionClosure(G1CardTableClaimTable* scan_state) : G1HeapRegionClosure(), _rem_set(G1CollectedHeap::heap()->rem_set()), _scan_state(scan_state), - _worker_id(worker_id), _completed(true), _per_worker_refine_data() { } @@ -164,8 +161,8 @@ class G1RefineRegionClosure : public G1HeapRegionClosure { }; G1ConcurrentRefineSweepTask::G1ConcurrentRefineSweepTask(G1CardTableClaimTable* scan_state, - G1ConcurrentRefineStats* stats, - uint max_workers) : + G1ConcurrentRefineStats* stats, + uint max_workers) : WorkerTask("G1 Refine Task"), _scan_state(scan_state), _stats(stats), @@ -176,7 +173,7 @@ G1ConcurrentRefineSweepTask::G1ConcurrentRefineSweepTask(G1CardTableClaimTable* void G1ConcurrentRefineSweepTask::work(uint worker_id) { jlong start = os::elapsed_counter(); - G1RefineRegionClosure sweep_cl(worker_id, _scan_state); + G1RefineRegionClosure sweep_cl(_scan_state); _scan_state->heap_region_iterate_from_worker_offset(&sweep_cl, worker_id, _max_workers); if (!sweep_cl._completed) { diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.cpp b/src/hotspot/share/gc/g1/g1FromCardCache.cpp deleted file mode 100644 index 8f5c84da0e3e..000000000000 --- a/src/hotspot/share/gc/g1/g1FromCardCache.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "gc/g1/g1FromCardCache.hpp" -#include "gc/shared/gc_globals.hpp" -#include "memory/padded.inline.hpp" -#include "runtime/globals.hpp" -#include "utilities/debug.hpp" - -uintptr_t** G1FromCardCache::_cache = nullptr; -uint G1FromCardCache::_max_reserved_regions = 0; -size_t G1FromCardCache::_static_mem_size = 0; -#ifdef ASSERT -uint G1FromCardCache::_max_workers = 0; -#endif - -void G1FromCardCache::initialize(uint max_reserved_regions) { - guarantee(max_reserved_regions > 0, "Heap size must be valid"); - guarantee(_cache == nullptr, "Should not call this multiple times"); - - _max_reserved_regions = max_reserved_regions; -#ifdef ASSERT - _max_workers = num_par_rem_sets(); -#endif - _cache = Padded2DArray::create_unfreeable(_max_reserved_regions, - num_par_rem_sets(), - &_static_mem_size); - - if (AlwaysPreTouch) { - invalidate(0, _max_reserved_regions); - } -} - -void G1FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { - guarantee((size_t)start_idx + new_num_regions <= max_uintx, - "Trying to invalidate beyond maximum region, from %u size %zu", - start_idx, new_num_regions); - uint end_idx = (start_idx + (uint)new_num_regions); - assert(end_idx <= _max_reserved_regions, "Must be within max."); - - for (uint i = 0; i < num_par_rem_sets(); i++) { - for (uint j = start_idx; j < end_idx; j++) { - set(i, j, InvalidCard); - } - } -} - -#ifndef PRODUCT -void G1FromCardCache::print(outputStream* out) { - for (uint i = 0; i < num_par_rem_sets(); i++) { - for (uint j = 0; j < _max_reserved_regions; j++) { - out->print_cr("_from_card_cache[%u][%u] = %zu.", - i, j, at(i, j)); - } - } -} -#endif - -uint G1FromCardCache::num_par_rem_sets() { - return G1ConcRefinementThreads + ConcGCThreads; -} - -void G1FromCardCache::clear(uint region_idx) { - uint num_par_remsets = num_par_rem_sets(); - for (uint i = 0; i < num_par_remsets; i++) { - set(i, region_idx, InvalidCard); - } -} diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.hpp b/src/hotspot/share/gc/g1/g1FromCardCache.hpp index 0a01e0102aed..5f759be0c4fb 100644 --- a/src/hotspot/share/gc/g1/g1FromCardCache.hpp +++ b/src/hotspot/share/gc/g1/g1FromCardCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,76 +25,44 @@ #ifndef SHARE_GC_G1_G1FROMCARDCACHE_HPP #define SHARE_GC_G1_G1FROMCARDCACHE_HPP -#include "memory/allStatic.hpp" -#include "utilities/ostream.hpp" +#include "gc/shared/gc_globals.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" -// G1FromCardCache remembers the most recently processed card on the heap on -// a per-region and per-thread basis. -class G1FromCardCache : public AllStatic { -private: - // Array of card indices. Indexed by heap region (rows) and thread (columns) to minimize - // thread contention. - // This order minimizes the time to clear all entries for a given region during region - // freeing. I.e. a single clear of a single memory area instead of multiple separate - // accesses with a large stride per region. - static uintptr_t** _cache; - static uint _max_reserved_regions; - static size_t _static_mem_size; -#ifdef ASSERT - static uint _max_workers; +// G1FromCardCache remembers which destination cset groups have been +// encountered while a worker scans the current from_card. +// +// Refinement and remembered set rebuild scan the heap linearly, visiting +// references from a card consecutively. Therefore, the cache only tracks +// the destination cset groups found while scanning the current card. The +// cache state is discarded when advancing to the next card. +// +// A scan can be suspended at a yield point. A GC may run while it is +// suspended and change the cset group assignments. Therefore, the cache +// must be reset before the scan resumes after every yield. +class G1FromCardCache { + // Worst case: each reference in a card targets a different cset group. + static constexpr uint MaxGroupsPerCard = MaxGCCardSizeInBytes / sizeof(narrowOop); - static void check_bounds(uint worker_id, uint region_idx) { - assert(worker_id < _max_workers, "Worker_id %u is larger than maximum %u", worker_id, _max_workers); - assert(region_idx < _max_reserved_regions, "Region_idx %u is larger than maximum %u", region_idx, _max_reserved_regions); - } -#endif - - // This card index indicates "no card for that entry" yet. This allows us to use the OS - // lazy backing of memory with zero-filled pages to avoid initial actual memory use. - // This means that the heap must not contain card zero. - static const uintptr_t InvalidCard = 0; + uintptr_t _from_card; + uint _num_cset_groups; + uint _cset_group_ids[MaxGroupsPerCard]; - // Gives an approximation on how many threads can be expected to add records to - // a remembered set in parallel. This is used for sizing the G1FromCardCache to - // decrease performance losses due to data structure sharing. - // Examples for quantities that influence this value are the maximum number of - // mutator threads, maximum number of concurrent refinement or GC threads. - static uint num_par_rem_sets(); + NONCOPYABLE(G1FromCardCache); public: - static void clear(uint region_idx); - - // Returns true if the given card is in the cache at the given location, or - // replaces the card at that location and returns false. - static bool contains_or_replace(uint worker_id, uint region_idx, uintptr_t card) { - uintptr_t card_in_cache = at(worker_id, region_idx); - if (card_in_cache == card) { - return true; - } else { - set(worker_id, region_idx, card); - return false; - } - } - - static uintptr_t at(uint worker_id, uint region_idx) { - DEBUG_ONLY(check_bounds(worker_id, region_idx);) - return _cache[region_idx][worker_id]; - } + G1FromCardCache() + : _from_card(0), + _num_cset_groups(0) {} - static void set(uint worker_id, uint region_idx, uintptr_t val) { - DEBUG_ONLY(check_bounds(worker_id, region_idx);) - _cache[region_idx][worker_id] = val; + // Discard the state associated with the _from_card. + void reset() { + _num_cset_groups = 0; } - static void initialize(uint max_reserved_regions); - - static void invalidate(uint start_idx, size_t num_regions); - - static void print(outputStream* out = tty) PRODUCT_RETURN; - - static size_t static_mem_size() { - return _static_mem_size; - } + // Returns true if cset_group_id has already been encountered while + // scanning from_card. Otherwise, records the id and returns false. + inline bool contains_or_add(uintptr_t from_card, uint cset_group_id); }; #endif // SHARE_GC_G1_G1FROMCARDCACHE_HPP diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp b/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp new file mode 100644 index 000000000000..9a4abac3bc81 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1FROMCARDCACHE_INLINE_HPP +#define SHARE_GC_G1_G1FROMCARDCACHE_INLINE_HPP + +#include "gc/g1/g1FromCardCache.hpp" + +bool G1FromCardCache::contains_or_add(uintptr_t from_card, uint cset_group_id) { + if (_from_card != from_card) { + _from_card = from_card; + _num_cset_groups = 0; + } + + for (uint i = 0; i < _num_cset_groups; i++) { + if (_cset_group_ids[i] == cset_group_id) { + return true; + } + } + + assert(_num_cset_groups < MaxGroupsPerCard, "from_card has too many destination cset groups"); + + _cset_group_ids[_num_cset_groups++] = cset_group_id; + return false; +} + +#endif // SHARE_GC_G1_G1FROMCARDCACHE_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp index 310cc4297c67..d6d39bafb34e 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp @@ -31,8 +31,14 @@ G1FullGCResetMetadataTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1Full _collector(collector) { } void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1HeapRegion* hr) { - assert(hr->is_humongous() || !hr->rem_set()->has_cset_group(), - "Non-humongous regions must not have cset group"); + if (hr->rem_set()->has_cset_group()) { + assert(hr->is_starts_humongous(), "Only humongous regions can retain a cset group"); + assert(hr->rem_set()->cset_group()->length() == 1, + "Humongous region cset group must contain exactly one region"); + + hr->rem_set()->cset_group()->clear_card_set(); + } + hr->rem_set()->clear(); hr->clear_both_card_tables(); _g1h->concurrent_mark()->reset_region_marking_state(hr); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 2c85e2fcc0d5..aee62a5ff68b 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -109,7 +109,12 @@ void G1HeapRegion::handle_evacuation_failure(bool retain) { move_to_old(); _rem_set->clean_code_roots(this); - _rem_set->clear(true /* only_cardset */, retain /* keep_tracked */); + assert(!_rem_set->has_cset_group(), "must not have a cset group"); + if (retain) { + assert(_rem_set->is_tracked(), "must be"); + } else { + _rem_set->set_state_untracked(); + } } void G1HeapRegion::unlink_from_list() { @@ -263,7 +268,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index, assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()), "invalid space boundaries"); - _rem_set = new G1HeapRegionRemSet(this); + _rem_set = new G1HeapRegionRemSet(); initialize(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index e2009b0e77d4..94b8633cd8ff 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -55,36 +55,19 @@ void G1HeapRegionRemSet::uninstall_cset_group() { _cset_group = nullptr; } -G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr) : +G1HeapRegionRemSet::G1HeapRegionRemSet() : _code_roots(), _cset_group(nullptr), - _hr(hr), _state(Untracked) { } G1HeapRegionRemSet::~G1HeapRegionRemSet() { assert(!has_cset_group(), "Still assigned to a CSet group"); } -void G1HeapRegionRemSet::clear_fcc() { - G1FromCardCache::clear(_hr->hrm_index()); -} - -void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { - if (!only_cardset) { - _code_roots.clear(); - } - clear_fcc(); - - if (has_cset_group()) { - card_set()->clear(); - assert(card_set()->occupied() == 0, "Should be clear."); - } - - if (!keep_tracked) { - set_state_untracked(); - } else { - assert(is_tracked(), "must be"); - } +void G1HeapRegionRemSet::clear() { + assert(card_set_is_empty(), "Card set must be empty"); + _code_roots.clear(); + set_state_untracked(); } void G1HeapRegionRemSet::reset_code_root_table_scanner() { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 3fc943a29516..70b32effd9d5 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -29,13 +29,13 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CodeRootSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" -#include "gc/g1/g1FromCardCache.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "utilities/bitMap.hpp" class G1CardSetMemoryManager; class G1CSetCandidateGroup; +class G1FromCardCache; class outputStream; class G1HeapRegionRemSet : public CHeapObj { @@ -46,13 +46,9 @@ class G1HeapRegionRemSet : public CHeapObj { // The collection set groups to which the region owning this RSet is assigned. G1CSetCandidateGroup* _cset_group; - G1HeapRegion* _hr; - // Cached value of heap base address. static HeapWord* _heap_base_address; - void clear_fcc(); - G1CardSet* card_set() { assert(has_cset_group(), "pre-condition"); return cset_group()->card_set(); @@ -64,10 +60,10 @@ class G1HeapRegionRemSet : public CHeapObj { } public: - G1HeapRegionRemSet(G1HeapRegion* hr); + G1HeapRegionRemSet(); ~G1HeapRegionRemSet(); - bool cardset_is_empty() const { + bool card_set_is_empty() const { return !has_cset_group() || card_set()->is_empty(); } @@ -98,7 +94,7 @@ class G1HeapRegionRemSet : public CHeapObj { } bool is_empty() const { - return (code_roots_list_length() == 0) && cardset_is_empty(); + return (code_roots_list_length() == 0) && card_set_is_empty(); } bool occupancy_less_or_equal_than(size_t occ) const { @@ -148,11 +144,10 @@ class G1HeapRegionRemSet : public CHeapObj { inline void set_state_updating(); inline void set_state_complete(); - inline void add_reference(OopOrNarrowOopStar from, uint tid); + inline void add_reference(OopOrNarrowOopStar from, G1FromCardCache& from_card_cache); - // The region is being reclaimed; clear its remset, and any mention of - // entries for this region in other remsets. - void clear(bool only_cardset = false, bool keep_tracked = false); + // Clear the region-specific remset state. + void clear(); void reset_code_root_table_scanner(); void reset_table_scanner(); @@ -168,7 +163,7 @@ class G1HeapRegionRemSet : public CHeapObj { // Returns the memory occupancy of all static data structures associated // with remembered sets. static size_t static_mem_size() { - return G1CardSet::static_mem_size() + G1FromCardCache::static_mem_size(); + return G1CardSet::static_mem_size(); } static void print_static_mem_size(outputStream* out); @@ -204,15 +199,7 @@ class G1HeapRegionRemSet : public CHeapObj { // consumed by the code roots. size_t code_roots_mem_size(); - static void invalidate_from_card_cache(uint start_idx, size_t num_regions) { - G1FromCardCache::invalidate(start_idx, num_regions); - } - #ifndef PRODUCT - static void print_from_card_cache() { - G1FromCardCache::print(); - } - static void test(); #endif }; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index f621b1318c1e..fb63bccd957e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -29,6 +29,7 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1FromCardCache.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -38,19 +39,16 @@ void G1HeapRegionRemSet::set_state_untracked() { if (_state == Untracked) { return; } - clear_fcc(); _state = Untracked; } void G1HeapRegionRemSet::set_state_updating() { guarantee(SafepointSynchronize::is_at_safepoint() && !is_tracked(), "Should only set to Updating from Untracked during safepoint but is %s", get_state_str()); - clear_fcc(); _state = Updating; } void G1HeapRegionRemSet::set_state_complete() { - clear_fcc(); _state = Complete; } @@ -123,18 +121,15 @@ uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { return pointer_delta(from, _heap_base_address, 1) >> CardTable::card_shift(); } -void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { - assert(has_cset_group(), "pre-condition"); +void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, G1FromCardCache& from_card_cache) { + precond(has_cset_group()); + precond(_state != Untracked); - assert(_state != Untracked, "must be"); - - uint cur_idx = _hr->hrm_index(); uintptr_t from_card = uintptr_t(from) >> CardTable::card_shift(); - if (G1FromCardCache::contains_or_replace(tid, cur_idx, from_card)) { + if (from_card_cache.contains_or_add(from_card, cset_group()->group_id())) { // We can't check whether the card is in the remembered set - the card container // may be coarsened just now. - //assert(contains_reference(from), "We just found " PTR_FORMAT " in the FromCardCache", p2i(from)); return; } diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index a61c9d17f70c..b6cbb765280d 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1OOPCLOSURES_HPP #include "classfile/classLoaderData.hpp" +#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/g1HeapRegionAttr.hpp" #include "memory/iterator.hpp" #include "oops/markWord.hpp" @@ -205,17 +206,16 @@ class G1RootRegionScanClosure : public ClaimMetadataVisitingOopIterateClosure { class G1ConcurrentRefineOopClosure: public BasicOopIterateClosure { G1CollectedHeap* _g1h; - uint _worker_id; + G1FromCardCache _from_card_cache; bool _has_ref_to_cset; bool _has_ref_to_old; public: - G1ConcurrentRefineOopClosure(G1CollectedHeap* g1h, uint worker_id) : + G1ConcurrentRefineOopClosure(G1CollectedHeap* g1h) : _g1h(g1h), - _worker_id(worker_id), + _from_card_cache(), _has_ref_to_cset(false), - _has_ref_to_old(false) { - } + _has_ref_to_old(false) {} bool has_ref_to_cset() const { return _has_ref_to_cset; } bool has_ref_to_old() const { return _has_ref_to_old; } @@ -229,11 +229,14 @@ class G1ConcurrentRefineOopClosure: public BasicOopIterateClosure { class G1RebuildRemSetClosure : public BasicOopIterateClosure { G1CollectedHeap* _g1h; - uint _worker_id; + G1FromCardCache _from_card_cache; public: - G1RebuildRemSetClosure(G1CollectedHeap* g1h, uint worker_id) : _g1h(g1h), _worker_id(worker_id) { - } + G1RebuildRemSetClosure(G1CollectedHeap* g1h) + : _g1h(g1h), + _from_card_cache() {} + + void reset_from_card_cache() { _from_card_cache.reset(); } template void do_oop_work(T* p); virtual void do_oop(oop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 80fb1be14ddb..aed36f8738fd 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,7 +164,7 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) { G1HeapRegion* from = _g1h->heap_region_containing(p); if (from->rem_set()->cset_group() != to_rem_set->cset_group()) { - to_rem_set->add_reference(p, _worker_id); + to_rem_set->add_reference(p, _from_card_cache); _has_ref_to_old = true; } } @@ -291,7 +291,7 @@ template void G1RebuildRemSetClosure::do_oop_work(T* p) { G1HeapRegion* from = _g1h->heap_region_containing(p); if (from->rem_set()->cset_group() != rem_set->cset_group()) { - rem_set->add_reference(p, _worker_id); + rem_set->add_reference(p, _from_card_cache); } } } diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 70fa7900805a..5261d39e715e 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -34,7 +34,6 @@ #include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineSweepTask.hpp" -#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/g1GCParPhaseTimesTracker.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" @@ -1078,7 +1077,10 @@ class G1MergeHeapRootsTask : public WorkerTask { // remembered sets for this region. // We want to continue collecting remembered set entries for humongous regions // that were not reclaimed. - r->rem_set()->clear(true /* only_cardset */, true /* keep_tracked */); + G1CSetCandidateGroup* group = r->rem_set()->cset_group(); + assert(group != nullptr, "must have a cset group"); + assert(group->length() == 1, "humongous regions cset group must have a single entry"); + group->clear_card_set(); } // Postcondition @@ -1264,8 +1266,7 @@ inline void check_card_ptr(CardTable::CardValue* card_ptr, G1CardTable* ct) { #endif } -G1RemSet::RefineResult G1RemSet::refine_card_concurrently(CardValue* const card_ptr, - const uint worker_id) { +G1RemSet::RefineResult G1RemSet::refine_card_concurrently(CardValue* const card_ptr) { assert(!_g1h->is_stw_gc_active(), "Only call concurrently"); G1CardTable* ct = _g1h->refinement_table(); check_card_ptr(card_ptr, ct); @@ -1295,7 +1296,7 @@ G1RemSet::RefineResult G1RemSet::refine_card_concurrently(CardValue* const card_ MemRegion dirty_region(start, MIN2(scan_limit, end)); assert(!dirty_region.is_empty(), "sanity"); - G1ConcurrentRefineOopClosure conc_refine_cl(_g1h, worker_id); + G1ConcurrentRefineOopClosure conc_refine_cl(_g1h); if (r->oops_on_memregion_seq_iterate_careful(dirty_region, &conc_refine_cl) != nullptr) { if (conc_refine_cl.has_ref_to_cset()) { return HasRefToCSet; diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index 4893e0839d00..4b079ae297b3 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -126,8 +126,7 @@ class G1RemSet: public CHeapObj { // Refine the region corresponding to "card_ptr". Must be called after // being filtered by clean_card_before_refine(), and after proper // fence/synchronization. - RefineResult refine_card_concurrently(CardValue* const card_ptr, - const uint worker_id); + RefineResult refine_card_concurrently(CardValue* const card_ptr); // Print accumulated summary info from the start of the VM. void print_summary_info(); diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp index 94f5466b8e0f..587ef2b6a12a 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp @@ -102,11 +102,17 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { // cycle as e.g. remembered set entries will always be added. if (r->is_starts_humongous() && !g1h->is_potential_eager_reclaim_candidate(r)) { // Handle HC regions with the HS region. + G1CSetCandidateGroup* group = r->rem_set()->cset_group(); + + assert(group != nullptr, "humongous start must have a cset group"); + assert(group->length() == 1, "humongous group must have only one region"); + + group->clear_card_set(); g1h->humongous_obj_regions_iterate(r, [&] (G1HeapRegion* r) { assert(!r->is_continues_humongous() || r->rem_set()->is_empty(), "Continues humongous region %u remset should be empty", r->hrm_index()); - r->rem_set()->clear(true /* only_cardset */); + r->rem_set()->set_state_untracked(); }); } diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 336f4bd59a12..2eeee2b0cac6 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -46,6 +46,8 @@ #include "gc/z/z_globals.hpp" #endif +constexpr uint MaxGCCardSizeInBytes = NOT_LP64(512) LP64_ONLY(1024); + #define GC_FLAGS(develop, \ develop_pd, \ product, \ @@ -523,7 +525,7 @@ \ product(uint, GCCardSizeInBytes, 512, \ "Card table entry size (in bytes) for card based collectors") \ - range(128, NOT_LP64(512) LP64_ONLY(1024)) \ + range(128, MaxGCCardSizeInBytes) \ constraint(GCCardSizeInBytesConstraintFunc,AtParse) // end of GC_FLAGS diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 7178d8f2b5f2..989c0b9c0fd5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -172,6 +172,7 @@ // These limitations will be addressed in future enhancements to the // existing implementation. +#include "gc/shared/gc_globals.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahCardStats.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" @@ -368,9 +369,7 @@ class ShenandoahCardCluster: public CHeapObj { static const uint8_t FirstStartBits = 0x7f; // Check that we have enough bits to store the largest possible offset into a card for an object start. - // The value for maximum card size is based on the constraints for GCCardSizeInBytes in gc_globals.hpp. - static const int MaxCardSize = NOT_LP64(512) LP64_ONLY(1024); - STATIC_ASSERT((MaxCardSize / HeapWordSize) - 1 <= FirstStartBits); + STATIC_ASSERT((MaxGCCardSizeInBytes / HeapWordSize) - 1 <= FirstStartBits); crossing_info* _object_starts; diff --git a/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp b/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp new file mode 100644 index 000000000000..f560bacd6f6e --- /dev/null +++ b/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/g1/g1FromCardCache.inline.hpp" +#include "unittest.hpp" + +TEST(G1FromCardCache, hit_and_miss) { + const uintptr_t from_card = 64; + const uint cset_group_a = 3; + const uint cset_group_b = 13; + const uint cset_group_high = 1024; + + G1FromCardCache cache; + + EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_a)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_a)); + + // Retain multiple cset groups for the same from_card. + EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_b)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_a)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_b)); + + // A group id is not an array index. + EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_high)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_high)); +} + +TEST(G1FromCardCache, from_card_transition) { + const uintptr_t from_card_a = 2; + const uintptr_t from_card_b = 3; + const uint cset_group_id = 17; + + G1FromCardCache cache; + + EXPECT_FALSE(cache.contains_or_add(from_card_a, cset_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card_a, cset_group_id)); + + // Discard previous from_card data. + EXPECT_FALSE(cache.contains_or_add(from_card_b, cset_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card_b, cset_group_id)); + + // Verify that it was discarded before. + EXPECT_FALSE(cache.contains_or_add(from_card_a, cset_group_id)); +} + +TEST(G1FromCardCache, cache_reset) { + const uintptr_t from_card = 17; + const uint cset_group_id = 17; + + G1FromCardCache cache; + + EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_id)); + + cache.reset(); + + EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_id)); +} From 3b3be26ac836b9615d686b65212bfb93be699daf Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 1 Sep 2026 08:46:27 +0000 Subject: [PATCH 169/223] 8390813: C2: Wrong entries in adlc commutative op lists Reviewed-by: qamai, gcao, fyang --- src/hotspot/share/adlc/formssel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 8abaa62982bb..167f19a8fde7 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3905,15 +3905,14 @@ void MatchNode::count_commutative_op(int& count) { "MaxI","MinI","MaxHF","MinHF","MaxF","MinF","MaxD","MinD", "MulI","MulL","MulHF","MulF","MulD", "OrI","OrL", - "XorI","XorL" - "UMax","UMin" + "XorI","XorL", }; static const char *commut_vector_op_list[] = { "AddVB", "AddVS", "AddVI", "AddVL", "AddVHF", "AddVF", "AddVD", "MulVB", "MulVS", "MulVI", "MulVL", "MulVHF", "MulVF", "MulVD", "AndV", "OrV", "XorV", "AndVMask", "OrVMask", "XorVMask", - "MaxVHF", "MinVHF", "MaxV", "MinV", "UMax","UMin" + "MaxVHF", "MinVHF", "MaxV", "MinV", "UMaxV", "UMinV", }; if (_lChild && _rChild && (_lChild->_lChild || _rChild->_lChild)) { From 9b81cf8c25c2584273f5295fbaab3106b0cef4dc Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 1 Sep 2026 09:26:09 +0000 Subject: [PATCH 170/223] 8387457: Test compiler/c2/Test6857159.java times out Reviewed-by: chagedorn, qamai --- .../jtreg/compiler/c2/Test6857159.java | 84 ------------------- .../compiler/c2/TestLoadKlassAntiDep.java | 58 +++++++++++++ 2 files changed, 58 insertions(+), 84 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/c2/Test6857159.java create mode 100644 test/hotspot/jtreg/compiler/c2/TestLoadKlassAntiDep.java diff --git a/test/hotspot/jtreg/compiler/c2/Test6857159.java b/test/hotspot/jtreg/compiler/c2/Test6857159.java deleted file mode 100644 index c60192643e9e..000000000000 --- a/test/hotspot/jtreg/compiler/c2/Test6857159.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 6857159 - * @summary local schedule failed with checkcast of Thread.currentThread() - * @library /test/lib - * @modules java.base/jdk.internal.misc - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:CompileCommand=compileonly,compiler.c2.Test6857159$ct0::run - * compiler.c2.Test6857159 - */ - -package compiler.c2; - -import jdk.test.whitebox.WhiteBox; - -public class Test6857159 extends Thread { - public static void main(String[] args) throws Exception { - var whiteBox = WhiteBox.getWhiteBox(); - var method = ct0.class.getDeclaredMethod("run"); - for (int i = 0; i < 20000; i++) { - Thread t = null; - switch (i % 3) { - case 0: - t = new ct0(); - break; - case 1: - t = new ct1(); - break; - case 2: - t = new ct2(); - break; - } - t.start(); - t.join(); - } - if (!whiteBox.isMethodCompiled(method)) { - throw new AssertionError(method + " didn't get compiled"); - } - } - - static class ct0 extends Test6857159 { - public void message() { } - - public void run() { - message(); - ct0 ct = (ct0) Thread.currentThread(); - ct.message(); - } - } - - static class ct1 extends ct0 { - public void message() { } - } - - static class ct2 extends ct0 { - public void message() { } - } -} diff --git a/test/hotspot/jtreg/compiler/c2/TestLoadKlassAntiDep.java b/test/hotspot/jtreg/compiler/c2/TestLoadKlassAntiDep.java new file mode 100644 index 000000000000..1582ede7d050 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestLoadKlassAntiDep.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 6857159 + * @summary local schedule failed with checkcast of Thread.currentThread() + * @modules java.base/jdk.internal.access + * @run main ${test.main.class} + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test + * -XX:CompileCommand=dontinline,${test.main.class}::notInlined + * ${test.main.class} + */ + +package compiler.c2; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +public class TestLoadKlassAntiDep { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + public static void main(String[] args) { + for (int i = 0; i < 50_000; i++) { + test(); + } + } + + static void notInlined() { } + + static Class test() { + notInlined(); + + // These intrinsics create immutable klass loads whose addresses depend on the carrier thread load + return JLA.currentCarrierThread().getClass().getSuperclass(); + } +} From 71e04e3d85db379a718e440e587f31812090265a Mon Sep 17 00:00:00 2001 From: April Ivy Date: Tue, 1 Sep 2026 09:37:59 +0000 Subject: [PATCH 171/223] 8390121: C2: StressBailout and VerifyIterativeGVN lead to nullptr push to igvn worklist Reviewed-by: qamai, dskantz --- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/phaseX.cpp | 3 +++ .../jtreg/compiler/debug/TestStressBailout.java | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 0a02854e8ba1..04247754b1a0 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3096,7 +3096,7 @@ void Compile::Optimize() { } assert(!has_vbox_nodes(), "sanity"); - if (!failing() && RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) { + if (RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) { Compile::TracePhase tp(_t_renumberLive); igvn_worklist()->ensure_empty(); // should be done with igvn { diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 0a9a82a20063..d8c59c01f4e3 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1195,6 +1195,9 @@ bool PhaseIterGVN::deep_revisit() { } void PhaseIterGVN::optimize(bool deep) { + // A correctly handled failure returns at the failing() call that raised it, so + // the compilation must never get here failed, with the graph already flushed. + assert(!C->failing_internal(), "should not run IGVN on a failed compilation"); bool deep_revisit_converged = false; DEBUG_ONLY(_num_processed = 0;) NOT_PRODUCT(init_verifyPhaseIterGVN();) diff --git a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java index f79cb679c413..64f023388e92 100644 --- a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java +++ b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java @@ -50,6 +50,16 @@ * @run main compiler.debug.TestStressBailout -XX:VerifyIterativeGVN=1111 */ +/* + * @test + * @key stress randomness + * @bug 8390121 + * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) + * @summary Bailouts between optimization phases must not reach IGVN verification + * @library /test/lib / + * @run main ${test.main.class} -XX:VerifyIterativeGVN=1110 -XX:+StressIGVN -XX:+StressIncrementalInlining + */ + public class TestStressBailout { static void runTest(int invprob, Stream vmArgs) throws Exception { From 6ad645714c9884bbb37068d560ee778befcd19d3 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 1 Sep 2026 10:48:05 +0000 Subject: [PATCH 172/223] 8391450: Aarch64: Remove the movk narrowKlass mode Reviewed-by: adinn, aph --- .../cpu/aarch64/compressedKlass_aarch64.cpp | 19 --------------- .../cpu/aarch64/macroAssembler_aarch64.cpp | 24 ------------------- .../cpu/aarch64/macroAssembler_aarch64.hpp | 1 - .../gtest/aarch64/test_assembler_aarch64.cpp | 19 +++++++++------ ...essedCPUSpecificClassSpaceReservation.java | 1 - 5 files changed, 12 insertions(+), 52 deletions(-) diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index 7cc2a004c40d..7d9acafddc09 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -98,25 +98,6 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size result = reserve_at_eor_compatible_address(size, aslr); } - // Movk-compatible reservation via probing. - if (result == nullptr) { - result = reserve_address_space_for_16bit_move(size, aslr); - } - - // Movk-compatible reservation via overallocation. - // If that failed, attempt to allocate at any 4G-aligned address. Let the system decide where. For ASLR, - // we now rely on the system. - // Compared with the probing done above, this has two disadvantages: - // - on a kernel with 52-bit address space we may get an address that has bits set between [48, 52). - // In that case, we may need two movk moves (not yet implemented). - // - this technique leads to temporary over-reservation of address space; it will spike the vsize of - // the process. Therefore it may fail if a vsize limit is in place (e.g. ulimit -v). - if (result == nullptr) { - constexpr size_t alignment = nth_bit(32); - log_debug(metaspace, map)("Trying to reserve at a 32-bit-aligned address"); - result = os::reserve_memory_aligned(size, alignment, mtNone); - } - return result; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 6d280d9e8ab9..0dada25f208c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5494,12 +5494,6 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode(address base, } } - const uint64_t shifted_base = - (uint64_t)base >> shift; - if ((shifted_base & 0xffff0000ffffffff) == 0) { - return KlassDecodeMovk; - } - return KlassDecodeFallback; } @@ -5545,14 +5539,6 @@ void MacroAssembler::emit_encode_klass_not_null(Register dst, Register src, Regi lsr(dst, dst, shift); break; - case KlassDecodeMovk: - if (shift != 0) { - ubfx(dst, src, shift, 32); - } else { - movw(dst, src); - } - break; - case KlassDecodeFallback: { mov(tmp, base); sub(dst, src, tmp); @@ -5609,16 +5595,6 @@ void MacroAssembler::emit_decode_klass_not_null(Register dst, Register src, Regi eor(dst, dst, (uint64_t)base); break; - case KlassDecodeMovk: { // 1-3 instructions - const uint64_t shifted_base = - (uint64_t)base >> shift; - - if (dst != src) movw(dst, src); - movk(dst, shifted_base >> 32, 32); - lsl(dst, dst, shift); - break; - } - case KlassDecodeFallback: { // 3-4 instructions mov(tmp, base); add(dst, tmp, src, LSL, shift); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 826f88fe85c3..13d5c6b8377d 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -104,7 +104,6 @@ class MacroAssembler: public Assembler { KlassDecodeNone, KlassDecodeZero, KlassDecodeXor, - KlassDecodeMovk, KlassDecodeFallback }; diff --git a/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp b/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp index 08d73d19655e..17de01505547 100644 --- a/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp +++ b/test/hotspot/gtest/aarch64/test_assembler_aarch64.cpp @@ -622,15 +622,20 @@ struct GtestFriendToMacroAssembler { build_and_run_encode_decode_klass((address)(right_n_bits(highest_xor_base_bit - lowest_xor_base_bit) << lowest_xor_base_bit), shift, MA::KlassDecodeXor); - // test movk-based - // Only bits in the third quadrant and not a valid immediate - build_and_run_encode_decode_klass((address)0x0000'A000'0000'0000ULL, 0, MA::KlassDecodeMovk); - // test Fallback mode. - // base has low bits that intersect with nKlass, no other mode would work - build_and_run_encode_decode_klass((address)(0x5'0000'0000ULL + os::vm_page_size()), + // We take fallback mode if base has low bits that intersect with nKlass, and/or if it is not a + // valid logical immediate + + // Not a logical immediate + build_and_run_encode_decode_klass((address)0x0000'A000'0000'0000ULL, + shift, MA::KlassDecodeFallback); + build_and_run_encode_decode_klass((address)0x0000'0005'0000'0000ULL, + shift, MA::KlassDecodeFallback); + + // Base spills into lower bits + build_and_run_encode_decode_klass((address)(0x2'0000'0000ULL + os::vm_page_size()), shift, MA::KlassDecodeFallback); - build_and_run_encode_decode_klass((address)(0x5'0000'0000ULL - os::vm_page_size()), + build_and_run_encode_decode_klass((address)(0x2'0000'0000ULL - os::vm_page_size()), shift, MA::KlassDecodeFallback); // a base that has ones in all four quadrants to trigger the full movz+3*movk path diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java index e9bdbe308077..d4287d34294d 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java @@ -84,7 +84,6 @@ private static void do_test(boolean CDS) throws IOException { } output.shouldContain("Trying to reserve at an EOR-compatible address"); output.shouldNotContain(tryReserveForZeroBased); - output.shouldMatch(tryReserveFor16bitMoveIntoQ3Regex); } else if (Platform.isPPC()) { if (CDS) { output.shouldNotContain(tryReserveForUnscaled); From 879c4a22b6cb13d29da4ebbd048c7b4a578b8ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Sep 2026 14:18:40 +0000 Subject: [PATCH 173/223] 8387756: JFR: subtle issue related to class loading constraints and early unwinds can lead to crashes and data corruption Reviewed-by: coleenp, egahlin --- src/hotspot/share/cds/lambdaFormInvokers.cpp | 3 + .../share/cds/lambdaProxyClassDictionary.cpp | 16 +- .../share/classfile/classLoaderData.cpp | 4 + .../share/classfile/systemDictionary.cpp | 14 +- .../share/classfile/systemDictionary.hpp | 8 +- src/hotspot/share/classfile/vmClasses.cpp | 13 +- .../instrumentation/jfrClassTransformer.cpp | 6 +- src/hotspot/share/jfr/jfr.cpp | 24 +- src/hotspot/share/jfr/jfr.hpp | 2 + .../checkpoint/types/traceid/jfrTraceId.cpp | 9 +- .../checkpoint/types/traceid/jfrTraceId.hpp | 18 +- .../types/traceid/jfrTraceId.inline.hpp | 66 +++++- .../types/traceid/jfrTraceIdMacros.hpp | 20 +- .../share/jfr/support/jfrClassDefineEvent.cpp | 205 ++++++++++++------ .../share/jfr/support/jfrClassDefineEvent.hpp | 3 +- .../share/jfr/support/jfrKlassUnloading.cpp | 13 +- .../share/jfr/support/jfrKlassUnloading.hpp | 3 +- .../share/jfr/support/jfrSymbolTable.cpp | 6 +- .../methodtracer/jfrClassFilterClosure.cpp | 47 ++-- .../methodtracer/jfrClassFilterClosure.hpp | 14 +- .../support/methodtracer/jfrMethodTracer.cpp | 162 +++++++++++--- .../support/methodtracer/jfrMethodTracer.hpp | 4 +- .../support/methodtracer/jfrTraceTagging.cpp | 100 +++++++-- .../support/methodtracer/jfrTraceTagging.hpp | 18 +- src/hotspot/share/oops/klass.cpp | 3 +- ...neEventWithViolatedLoadingConstraints.java | 149 +++++++++++++ 26 files changed, 737 insertions(+), 193 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/runtime/TestClassDefineEventWithViolatedLoadingConstraints.java diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 5cfb73d2f6ce..9b87438ff118 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -225,6 +225,9 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, cl_info, CHECK); + // The result InstanceKlass* is never used during the JVM process lifetime. + // We create it only for writing to the CDS archive, and so it need not be monitored by JVMTI or JFR. + assert(result->java_mirror() != nullptr, "must be"); RegeneratedClasses::add_class(InstanceKlass::cast(klass), result); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index 3c28bf06adf9..07b804c8ded4 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -34,6 +34,9 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif DumpTimeLambdaProxyClassInfo::~DumpTimeLambdaProxyClassInfo() { if (_proxy_klasses != nullptr) { @@ -318,6 +321,9 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(const RunTime InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(InstanceKlass* lambda_ik, InstanceKlass* caller_ik, TRAPS) { + + EventClassLoad class_load_event; + Handle class_loader(THREAD, caller_ik->class_loader()); Handle protection_domain; PackageEntry* pkg_entry = caller_ik->package(); @@ -359,20 +365,22 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* nest_host = caller_ik->nest_host(THREAD); assert(nest_host == shared_nest_host, "mismatched nest host"); - EventClassLoad class_load_event; + JFR_ONLY(Jfr::on_definition(lambda_ik, THREAD);) // Add to class hierarchy, and do possible deoptimizations. lambda_ik->add_to_hierarchy(THREAD); + assert(lambda_ik->is_loaded(), "Must be in at least loaded state"); // But, do not add to dictionary. + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader()));) + } + lambda_ik->link_class(CHECK_NULL); // notify jvmti if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, lambda_ik); } - if (class_load_event.should_commit()) { - JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader()));) - } lambda_ik->initialize(CHECK_NULL); diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index b773569ad7b8..27a899481a8f 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -81,6 +81,9 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = nullptr; @@ -899,6 +902,7 @@ void ClassLoaderData::free_deallocate_list() { HeapShared::remove_scratch_resolved_references((ConstantPool*)m); MetadataFactory::free_metadata(this, (ConstantPool*)m); } else if (m->is_klass()) { + JFR_ONLY(Jfr::on_deallocation(static_cast(m));) if (!((Klass*)m)->is_inline_klass()) { MetadataFactory::free_metadata(this, (InstanceKlass*)m); } else { diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 6141eeb7bd04..dbbc4196c7f7 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -837,6 +837,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( cl_info, CHECK_NULL); assert(k != nullptr, "no klass created"); + assert(k->class_loader_data() == loader_data, "invariant"); // Hidden classes that are not strong must update ClassLoaderData holder // so that they can be unloaded when the mirror is no longer referenced. @@ -844,8 +845,11 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror())); } + JFR_ONLY(Jfr::on_definition(k, THREAD);) + // Add to class hierarchy, and do possible deoptimizations. k->add_to_hierarchy(THREAD); + assert(k->is_loaded(), "Must be in at least loaded state"); // But, do not add to dictionary. if (class_load_event.should_commit()) { @@ -950,7 +954,6 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, InstanceKlass* ik, PackageEntry* pkg_entry, Handle class_loader) { - assert(!ModuleEntryTable::javabase_moduleEntry()->is_patched(), "Cannot use sharing if java.base is patched"); @@ -1334,7 +1337,11 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA ik->restore_unshareable_info(loader_data, pd, pkg_entry, CHECK); load_shared_class_misc(ik, loader_data); + + JFR_ONLY(Jfr::on_definition(ik, THREAD);) + ik->add_to_hierarchy(THREAD); + assert(ik->is_loaded(), "Must be in at least loaded state"); if (!ik->is_hidden()) { update_dictionary(THREAD, ik, loader_data); @@ -1343,8 +1350,6 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA if (class_load_event.should_commit()) { JFR_ONLY(post_class_load_event(&class_load_event, ik, loader_data);) } - - assert(ik->is_loaded(), "Must be in at least loaded state"); } #endif // INCLUDE_CDS @@ -1572,8 +1577,11 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load JavaCalls::call(&result, m, &args, CHECK); } + JFR_ONLY(Jfr::on_definition(k, THREAD);) + // Add to class hierarchy, and do possible deoptimizations. k->add_to_hierarchy(THREAD); + assert(k->is_loaded(), "Must be in at least loaded state"); // Add to systemDictionary - so other classes can see it. // Grabs and releases SystemDictionary_lock diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 4852ebe533a6..7a5bb1ec64ab 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -344,10 +344,6 @@ class SystemDictionary : AllStatic { static InstanceKlass* find_or_define_instance_class(Symbol* class_name, Handle class_loader, InstanceKlass* k, TRAPS); - JFR_ONLY(static void post_class_load_event(EventClassLoad* event, - const InstanceKlass* k, - const ClassLoaderData* init_cld);) - public: static bool is_system_class_loader(oop class_loader); static bool is_platform_class_loader(oop class_loader); @@ -362,6 +358,10 @@ class SystemDictionary : AllStatic { // Return Symbol or throw exception if name given is can not be a valid Symbol. static Symbol* class_name_symbol(const char* name, Symbol* exception, TRAPS); + + JFR_ONLY(static void post_class_load_event(EventClassLoad* event, + const InstanceKlass* k, + const ClassLoaderData* init_cld);) }; #endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 00d209a05ca5..1dde8b904a3c 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,9 @@ #include "oops/instanceStackChunkKlass.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/globals.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif InstanceKlass* vmClasses::_klasses[static_cast(vmClassID::LIMIT)] = { nullptr /*, nullptr...*/ }; @@ -260,11 +263,15 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load klass->restore_unshareable_info(loader_data, domain, nullptr, THREAD); SystemDictionary::load_shared_class_misc(klass, loader_data); - Dictionary* dictionary = loader_data->dictionary(); - dictionary->add_klass(THREAD, klass->name(), klass); + + JFR_ONLY(Jfr::on_definition(klass, THREAD)); + klass->add_to_hierarchy(THREAD); assert(klass->is_loaded(), "Must be in at least loaded state"); + Dictionary* dictionary = loader_data->dictionary(); + dictionary->add_klass(THREAD, klass->name(), klass); + if (class_load_event.should_commit()) { JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, klass, loader_data);) } diff --git a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp index ed478509f1f4..1c7fc571e65c 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp @@ -97,8 +97,9 @@ InstanceKlass* JfrClassTransformer::create_instance_klass(InstanceKlass*& ik, Cl void JfrClassTransformer::copy_traceid(const InstanceKlass* ik, const InstanceKlass* new_ik) { assert(ik != nullptr, "invariant"); assert(new_ik != nullptr, "invariant"); + assert(new_ik->trace_id() == 0, "invariant"); new_ik->set_trace_id(ik->trace_id()); - assert(TRACE_ID(ik) == TRACE_ID(new_ik), "invariant"); + ik->set_trace_id(0); } InstanceKlass* JfrClassTransformer::create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) { @@ -179,7 +180,8 @@ void JfrClassTransformer::rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlas assert(ik != nullptr, "invariant"); assert(new_ik != nullptr, "invariant"); assert(thread != nullptr, "invariant"); - assert(TRACE_ID(ik) == TRACE_ID(new_ik), "invariant"); + assert(TRACE_ID(ik) == 0, "invariant"); + assert(TRACE_ID(ik) != TRACE_ID(new_ik), "invariant"); assert(!thread->has_pending_exception(), "invariant"); // Assign original InstanceKlass* back onto "its" parser object for proper destruction. parser.set_klass_to_deallocate(ik); diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index b30f80d23b7b..cc0146c52536 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -28,6 +28,7 @@ #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" @@ -35,6 +36,7 @@ #include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" +#include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" @@ -43,7 +45,7 @@ #include "oops/klass.hpp" #include "runtime/java.hpp" #include "runtime/javaThread.hpp" - +#include "runtime/safepoint.hpp" bool Jfr::is_enabled() { return JfrRecorder::is_enabled(); @@ -175,6 +177,26 @@ void Jfr::on_report_java_out_of_memory() { } } +void Jfr::on_definition(const InstanceKlass* ik, JavaThread* jt) { + const bool from_boot_loader_modules_image = JfrTraceId::has_preload_bootloader_bit(ik); + if (from_boot_loader_modules_image) { + JfrTraceId::clear_preload_bootloader_bit(ik); + } + if (JfrTraceId::has_preload_sticky_bit(ik)) { + assert(JfrMethodTracer::in_use(), "invariant"); + JfrMethodTracer::on_definition(ik, jt); + } + JfrClassDefineEvent::send_event(ik, from_boot_loader_modules_image, jt); +} + +void Jfr::on_deallocation(const Klass* k) { + assert(k != nullptr, "invariant"); + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + if (JfrMethodTracer::in_use() && JfrTraceId::has_sticky_bit(k)) { + JfrKlassUnloading::add_to_unloaded_set(k); + } +} + #if INCLUDE_CDS void Jfr::on_restoration(const Klass* k, JavaThread* jt) { assert(k != nullptr, "invariant"); diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index ac6a232dda1b..e1bc6834a18f 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -80,6 +80,8 @@ class Jfr : AllStatic { static bool has_sample_request(JavaThread* jt); static void check_and_process_sample_request(JavaThread* jt); static void on_report_java_out_of_memory(); + static void on_definition(const InstanceKlass* ik, JavaThread* jt); + static void on_deallocation(const Klass* k); CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp index 405fa25baff6..0715ad87b9c0 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -292,3 +292,10 @@ void JfrTraceId::untag_jdk_jfr_event_sub(const Klass* k) { } assert(IS_NOT_AN_EVENT_SUB_KLASS(k), "invariant"); } + +#ifdef ASSERT +traceid JfrTraceId::preload_bits(const Klass* k) { + assert(k != nullptr, "invariant"); + return PRELOAD_TAG_BITS_OF(k); +} +#endif diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp index f10782be0eab..0c95fd7c5a71 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,8 +146,20 @@ class JfrTraceId : public AllStatic { static void set_sticky_bit(const Method* method); static void clear_sticky_bit(const Klass* k); static void clear_sticky_bit(const Method* method); - static bool has_timing_bit(const InstanceKlass* scratch_klass); - static void set_timing_bit(const InstanceKlass* scratch_klass); + static bool has_timing_bit(const InstanceKlass* ik); + static void set_timing_bit(const InstanceKlass* ik); + static void clear_timing_bit(const InstanceKlass* ik); + + // Preload tag bits (only valid during class loading, before a klass is defined) + static bool has_preload_sticky_bit(const Klass* k); + static void set_preload_sticky_bit(const Klass* k); + static void clear_preload_sticky_bit(const Klass* k); + + static bool has_preload_bootloader_bit(const Klass* k); + static void set_preload_bootloader_bit(const Klass* k); + static void clear_preload_bootloader_bit(const Klass* k); + + DEBUG_ONLY(static traceid preload_bits(const Klass* k);) }; #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp index 2af1080820f4..e37e08d090f6 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,16 +209,64 @@ inline void JfrTraceId::clear_sticky_bit(const Method* method) { assert(!JfrTraceId::has_sticky_bit(method), "invariant"); } -inline bool JfrTraceId::has_timing_bit(const InstanceKlass* scratch_klass) { - assert(scratch_klass != nullptr, "invariant"); - return HAS_TIMING_BIT(scratch_klass); +inline bool JfrTraceId::has_timing_bit(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + return HAS_TIMING_BIT(ik); +} + +inline void JfrTraceId::set_timing_bit(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(!has_timing_bit(ik), "invariant"); + SET_TIMING_BIT(ik); + assert(has_timing_bit(ik), "invariant"); +} + +inline void JfrTraceId::clear_timing_bit(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(has_timing_bit(ik), "invariant"); + CLEAR_TIMING_BIT(ik); + assert(!has_timing_bit(ik), "invariant"); +} + +inline bool JfrTraceId::has_preload_sticky_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + return HAS_PRELOAD_TAG_BIT_STICKY(k); } -inline void JfrTraceId::set_timing_bit(const InstanceKlass* scratch_klass) { - assert(scratch_klass != nullptr, "invariant"); - assert(!has_timing_bit(scratch_klass), "invariant"); - SET_TIMING_BIT(scratch_klass); - assert(has_timing_bit(scratch_klass), "invariant"); +inline void JfrTraceId::set_preload_sticky_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + assert(!has_preload_sticky_bit(k), "invariant"); + SET_PRELOAD_TAG_BIT_STICKY(k); + assert(has_preload_sticky_bit(k), "invariant"); +} + +inline void JfrTraceId::clear_preload_sticky_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + assert(has_preload_sticky_bit(k), "invariant"); + CLEAR_PRELOAD_TAG_BIT_STICKY(k); + assert(!has_preload_sticky_bit(k), "invariant"); +} + +inline bool JfrTraceId::has_preload_bootloader_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + return HAS_PRELOAD_TAG_BIT_BOOTLOADER(k); +} + +inline void JfrTraceId::set_preload_bootloader_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + assert(!has_preload_bootloader_bit(k), "invariant"); + SET_PRELOAD_TAG_BIT_BOOTLOADER(k); + assert(has_preload_bootloader_bit(k), "invariant"); +} + +inline void JfrTraceId::clear_preload_bootloader_bit(const Klass* k) { + assert(k != nullptr, "invariant"); + assert(has_preload_bootloader_bit(k), "invariant"); + CLEAR_PRELOAD_TAG_BIT_BOOTLOADER(k); + assert(!has_preload_bootloader_bit(k), "invariant"); } #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEID_INLINE_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp index 27cf66cc1fe7..10ab11dde99f 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,6 +66,12 @@ #define TAG_BITS (EPOCH_1_METHOD_BIT | EPOCH_0_METHOD_BIT | EPOCH_1_BIT | EPOCH_0_BIT) #define ALL_BITS (META_BITS | EVENT_BITS | TAG_BITS) #define ALL_BITS_MASK (~(ALL_BITS)) +#define PRELOAD_TAG_BIT_STICKY (EPOCH_1_METHOD_BIT) +#define PRELOAD_TAG_BIT_STICKY_MASK (~(PRELOAD_TAG_BIT_STICKY)) +#define PRELOAD_TAG_BIT_BOOTLOADER (EPOCH_0_METHOD_BIT) +#define PRELOAD_TAG_BIT_BOOTLOADER_MASK (~(PRELOAD_TAG_BIT_BOOTLOADER)) +#define PRELOAD_TAG_BITS (PRELOAD_TAG_BIT_STICKY | PRELOAD_TAG_BIT_BOOTLOADER) +#define PRELOAD_TAG_BITS_CLEAR_MASK (~(PRELOAD_TAG_BITS)) // epoch relative bits #define THIS_EPOCH_BIT (JfrTraceIdEpoch::this_epoch_bit()) @@ -78,19 +84,21 @@ // operators #define TRACE_ID_RAW(ptr) (JfrTraceIdBits::load(ptr)) #define TRACE_ID(ptr) (TRACE_ID_RAW(ptr) >> TRACE_ID_SHIFT) -#define TRACE_ID_MASKED(ptr) (TRACE_ID_RAW(ptr) & ALL_BITS_MASK) +#define TRACE_ID_MASKED(ptr, mask) (TRACE_ID_RAW(ptr) & mask) +#define TRACE_ID_MASKED_ALL_BITS(ptr) (TRACE_ID_MASKED(ptr, ALL_BITS_MASK)) #define TRACE_ID_PREDICATE(ptr, bits) ((TRACE_ID_RAW(ptr) & bits) != 0) #define TRACE_ID_TAG(ptr, bits) (JfrTraceIdBits::store(bits, ptr)) #define TRACE_ID_TAG_CAS(ptr, bits) (JfrTraceIdBits::cas(bits, ptr)) #define TRACE_ID_MASK_CLEAR(ptr, mask) (JfrTraceIdBits::mask_store(mask, ptr)) #define TRACE_ID_META_TAG(ptr, bits) (JfrTraceIdBits::meta_store(bits, ptr)) #define TRACE_ID_META_MASK_CLEAR(ptr, mask) (JfrTraceIdBits::meta_mask_store(mask, ptr)) -#define METHOD_ID(kls, method) (TRACE_ID_MASKED(kls) | (method)->orig_method_idnum()) +#define METHOD_ID(kls, method) (TRACE_ID_MASKED_ALL_BITS(kls) | (method)->orig_method_idnum()) #define METHOD_FLAG_PREDICATE(method, bits) ((method)->is_trace_flag_set(bits)) #define METHOD_FLAG_TAG(method, bits) (JfrTraceIdBits::store(bits, method)) #define METHOD_META_TAG(method, bits) (JfrTraceIdBits::meta_store(bits, method)) #define METHOD_FLAG_CLEAR(method, bits) (JfrTraceIdBits::clear_cas(bits, method)) #define METHOD_META_MASK_CLEAR(method, mask) (JfrTraceIdBits::meta_mask_store(mask, method)) +#define PRELOAD_TAG_BITS_OF(ptr) (TRACE_ID_MASKED(ptr, PRELOAD_TAG_BITS)) // predicates #define USED_THIS_EPOCH(ptr) (TRACE_ID_PREDICATE(ptr, (STICKY_BIT | TRANSIENT_BIT | THIS_EPOCH_BIT))) @@ -110,6 +118,8 @@ #define METHOD_FLAG_USED_PREVIOUS_EPOCH_BIT(method) (METHOD_FLAG_PREDICATE(method, (PREVIOUS_EPOCH_BIT))) #define METHOD_FLAG_NOT_USED_PREVIOUS_EPOCH(method) (!(METHOD_FLAG_USED_PREVIOUS_EPOCH(method))) #define IS_METHOD_BLESSED(method) (METHOD_FLAG_PREDICATE(method, BLESSED_METHOD_BIT)) +#define HAS_PRELOAD_TAG_BIT_STICKY(ptr) (TRACE_ID_PREDICATE(ptr, PRELOAD_TAG_BIT_STICKY)) +#define HAS_PRELOAD_TAG_BIT_BOOTLOADER(ptr) (TRACE_ID_PREDICATE(ptr, PRELOAD_TAG_BIT_BOOTLOADER)) // setters #define SET_USED_THIS_EPOCH(ptr) (TRACE_ID_TAG(ptr, THIS_EPOCH_BIT)) @@ -119,6 +129,10 @@ #define CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(kls) (TRACE_ID_MASK_CLEAR(kls, PREVIOUS_EPOCH_METHOD_AND_CLASS_BIT_MASK)) #define CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method) (METHOD_FLAG_CLEAR(method, PREVIOUS_EPOCH_BIT)) #define BLESS_METHOD(method) (METHOD_FLAG_TAG(method, BLESSED_METHOD_BIT)) +#define SET_PRELOAD_TAG_BIT_STICKY(ptr) (TRACE_ID_TAG(ptr, PRELOAD_TAG_BIT_STICKY)) +#define CLEAR_PRELOAD_TAG_BIT_STICKY(ptr) (TRACE_ID_MASK_CLEAR(ptr, PRELOAD_TAG_BIT_STICKY_MASK)) +#define SET_PRELOAD_TAG_BIT_BOOTLOADER(ptr) (TRACE_ID_TAG(ptr, PRELOAD_TAG_BIT_BOOTLOADER)) +#define CLEAR_PRELOAD_TAG_BIT_BOOTLOADER(ptr) (TRACE_ID_MASK_CLEAR(ptr, PRELOAD_TAG_BIT_BOOTLOADER_MASK)) // types #define IS_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_KLASS)) diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp index e9266ce171ad..acc8661d44fb 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,16 @@ #include "classfile/classFileParser.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/symbolTable.hpp" #include "jfr/instrumentation/jfrClassTransformer.hpp" +#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrSymbolTable.hpp" #include "jfrfiles/jfrEventClasses.hpp" +#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" +#include "oops/oopsHierarchy.hpp" #include "runtime/javaThread.hpp" /* @@ -50,8 +54,7 @@ static inline bool is_unnamed_module(const ModuleEntry* module) { return module == nullptr || !module->is_named(); } -static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) { - assert(jt != nullptr, "invariant"); +static inline bool is_jdk_module(const ModuleEntry* module) { if (is_unnamed_module(module)) { return false; } @@ -60,30 +63,81 @@ static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) { return is_jdk_module(module_symbol->as_C_string()); } -static inline bool is_jdk_module(const InstanceKlass* ik, JavaThread* jt) { +static inline bool is_jdk_module(const InstanceKlass* ik) { assert(ik != nullptr, "invariant"); - assert(jt != nullptr, "invariant"); - return is_jdk_module(ik->module(), jt); + return is_jdk_module(ik->module()); } -static traceid module_path(const InstanceKlass* ik, JavaThread* jt) { +static const char* module_source(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); const ModuleEntry* const module_entry = ik->module(); if (is_unnamed_module(module_entry)) { - return 0; + return nullptr; } const char* const module_name = module_entry->name()->as_C_string(); assert(module_name != nullptr, "invariant"); if (is_jdk_module(module_name)) { const size_t module_name_len = strlen(module_name); - char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/" - jio_snprintf(path, module_name_len + 6, "%s%s", "jrt:/", module_name); - return JfrSymbolTable::add(path); + char* const source = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/" + jio_snprintf(source, module_name_len + 6, "%s%s", "jrt:/", module_name); + return source; + } + return nullptr; +} + +// java_mirror -> ProtectionDomain -> CodeSource + +static const char* allocate(oop string, JavaThread* jt) { + char* str = nullptr; + const typeArrayOop value = java_lang_String::value(string); + if (value != nullptr) { + const size_t length = java_lang_String::utf8_length(string, value); + str = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, length + 1); + java_lang_String::as_utf8_string(string, value, str, length + 1); + } + return str; +} + +static int compute_field_offset(const Klass* klass, const char* field_name, const char* field_signature) { + assert(klass != nullptr, "invariant"); + Symbol* const name = SymbolTable::new_symbol(field_name); + assert(name != nullptr, "invariant"); + Symbol* const signature = SymbolTable::new_symbol(field_signature); + assert(signature != nullptr, "invariant"); + assert(klass->is_instance_klass(), "invariant"); + fieldDescriptor fd; + InstanceKlass::cast(klass)->find_field(name, signature, false, &fd); + return fd.offset(); +} + +static const char* location_no_frag_string(oop codesource, JavaThread* jt) { + assert(codesource != nullptr, "invariant"); + static int loc_no_frag_offset = compute_field_offset(codesource->klass(), "locationNoFragString", "Ljava/lang/String;"); + guarantee(loc_no_frag_offset > 0, "invariant"); + oop string = codesource->obj_field(loc_no_frag_offset); + return string != nullptr ? allocate(string, jt) : nullptr; +} + +static oop code_source(oop pd) { + assert(pd != nullptr, "invariant"); + static int codesource_offset = compute_field_offset(pd->klass(), "codesource", "Ljava/security/CodeSource;"); + return pd->obj_field(codesource_offset); +} + +static const char* code_source(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->java_mirror() != nullptr, "invariant"); + oop pd = java_lang_Class::protection_domain(ik->java_mirror()); + if (pd == nullptr) { + return nullptr; } - return 0; + oop cs = code_source(pd); + return cs != nullptr ? location_no_frag_string(cs, jt) : nullptr; } -static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) { +// Misc source info + +static const char* caller_source(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); assert(jt != nullptr, "invariant"); assert(ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); @@ -93,98 +147,107 @@ static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) { const char* caller_name = caller->external_name(); assert(caller_name != nullptr, "invariant"); const size_t caller_name_len = strlen(caller_name); - char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of " - jio_snprintf(path, caller_name_len + 13, "%s%s", "instance of ", caller_name); - return JfrSymbolTable::add(path); + char* const source = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of " + jio_snprintf(source, caller_name_len + 13, "%s%s", "instance of ", caller_name); + return source; } - return 0; + return nullptr; } -static traceid class_loader_path(const InstanceKlass* ik, JavaThread* jt) { +static const char* class_loader_source(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); assert(jt != nullptr, "invariant"); assert(!ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); oop class_loader = ik->class_loader_data()->class_loader(); - const char* class_loader_name = class_loader->klass()->external_name(); - return class_loader_name != nullptr ? JfrSymbolTable::add(class_loader_name) : 0; + return class_loader->klass()->external_name(); } -static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) { - return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr; +static const char* misc_source(const InstanceKlass* ik, JavaThread* jt) { + const char* source; + if (is_jdk_module(ik)) { + source = module_source(ik, jt); + } else if (ik->class_loader_data()->is_the_null_class_loader_data()) { + source = caller_source(ik, jt); + } else { + source = class_loader_source(ik, jt); + } + return source; } -static traceid get_source(const InstanceKlass* ik, JavaThread* jt) { - traceid source_id = 0; - if (is_jdk_module(ik, jt)) { - source_id = module_path(ik, jt); - } else if (ik->class_loader_data()->is_the_null_class_loader_data()) { - source_id = caller_path(ik, jt); +/* + * Ordering: + * + * 1. from_boot_loader_modules_image -> module_source + * 2. code source -> the java_mirror->ProtectionDomain->CodeSource->locationNoFragString representation + * 3. misc source -> assorted source constants as a function of state (similar to log output) + */ +static const char* source(const InstanceKlass* ik, bool from_boot_loader_modules_image, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + const char* s = nullptr; + if (from_boot_loader_modules_image) { + assert(is_jdk_module(ik), "invariant"); + s = module_source(ik, jt); } else { - source_id = class_loader_path(ik, jt); + s = code_source(ik, jt); + if (s == nullptr) { + s = misc_source(ik, jt); + } } - return source_id; + return s; } -static inline void send_event(const InstanceKlass* ik, traceid source_id) { - EventClassDefine event; - event.set_definedClass(ik); - event.set_definingClassLoader(ik->class_loader_data()); - event.set_source(source_id); - event.commit(); +static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) { + return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr; } void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt) { assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invarinat"); assert(ik->trace_id() != 0, "invariant"); assert(!parser.is_internal(), "invariant"); assert(jt != nullptr, "invariant"); - - if (EventClassDefine::is_enabled() && is_not_retransforming(ik, jt)) { - ResourceMark rm(jt); - traceid source_id = 0; - const ClassFileStream& stream = parser.stream(); - if (stream.source() != nullptr) { - if (stream.from_boot_loader_modules_image()) { - assert(is_jdk_module(ik, jt), "invariant"); - source_id = module_path(ik, jt); - } else { - source_id = JfrSymbolTable::add(stream.source()); - } - } else { - source_id = get_source(ik, jt); + if (is_not_retransforming(ik, jt)) { + if (parser.stream().from_boot_loader_modules_image()) { + JfrTraceId::set_preload_bootloader_bit(ik); } - send_event(ik, source_id); } } #if INCLUDE_CDS -static traceid get_source(const AOTClassLocation* cl, JavaThread* jt) { - assert(cl != nullptr, "invariant"); - assert(!cl->is_modules_image(), "invariant"); - const char* const path = cl->path(); - assert(path != nullptr, "invariant"); - size_t len = strlen(path); - const char* file_type = cl->file_type_string(); - assert(file_type != nullptr, "invariant"); - len += strlen(file_type) + 3; // ":/" + null - char* const url = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, len); - jio_snprintf(url, len, "%s%s%s", file_type, ":/", path); - return JfrSymbolTable::add(url); -} - void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invariant"); assert(ik->trace_id() != 0, "invariant"); - assert(jt != nullptr, "invariant"); - - if (EventClassDefine::is_enabled()) { - ResourceMark rm(jt); - assert(is_not_retransforming(ik, jt), "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);) + assert(is_not_retransforming(ik, jt), "invariant"); + if (!ik->defined_by_other_loaders()) { const int index = ik->shared_classpath_index(); assert(index >= 0, "invariant"); const AOTClassLocation* const cl = AOTClassLocationConfig::runtime()->class_location_at(index); assert(cl != nullptr, "invariant"); - send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); + if (cl->is_modules_image()) { + JfrTraceId::set_preload_bootloader_bit(ik); + } } } #endif + +static inline void commit_event(const InstanceKlass* ik, const char* s) { + assert(ik != nullptr, "invariant"); + EventClassDefine event; + event.set_definedClass(ik); + event.set_definingClassLoader(ik->class_loader_data()); + event.set_source(s != nullptr ? JfrSymbolTable::add(s) : 0); + event.commit(); +} + +void JfrClassDefineEvent::send_event(const InstanceKlass* ik, bool from_boot_loader_modules_image, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invariant"); + assert(is_not_retransforming(ik, jt), "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);) + if (EventClassDefine::is_enabled()) { + ResourceMark rm(jt); + commit_event(ik, source(ik, from_boot_loader_modules_image, jt)); + } +} diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp index 3e242d8e4f2e..496ada13ad30 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ class JavaThread; class JfrClassDefineEvent : AllStatic { public: static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); + static void send_event(const InstanceKlass* k, bool from_boot_loader_modules_image, JavaThread* jt); CDS_ONLY(static void on_restoration(const InstanceKlass* ik, JavaThread* jt);) }; diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp index bf285c3f41e9..af4ae8a86049 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp @@ -73,11 +73,13 @@ void JfrKlassUnloading::clear() { get_unload_set_previous_epoch()->clear(); } -static void add_to_unloaded_klass_set(traceid klass_id) { +void JfrKlassUnloading::add_to_unloaded_set(const Klass* k) { + assert(k != nullptr, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(USED_ANY_EPOCH(k), "invariant"); JfrCHeapTraceIdSet* const unload_set = get_unload_set(); assert(unload_set != nullptr, "invariant"); - unload_set->add(klass_id); + unload_set->add(JfrTraceId::load_raw(k)); } #if INCLUDE_MANAGEMENT @@ -99,8 +101,11 @@ bool JfrKlassUnloading::on_unload(const Klass* k) { if (IS_JDK_JFR_EVENT_SUBKLASS(k)) { ++event_klass_unloaded_count; } - add_to_unloaded_klass_set(JfrTraceId::load_raw(k)); - return USED_THIS_EPOCH(k) || USED_PREVIOUS_EPOCH(k); + if (USED_ANY_EPOCH(k)) { + add_to_unloaded_set(k); + return true; + } + return false; } static inline bool is_unloaded(const JfrCHeapTraceIdSet* set, const traceid& id) { diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp index 25ff820fc095..994320cc1119 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ class Klass; class JfrKlassUnloading : AllStatic { public: static bool on_unload(const Klass* k); + static void add_to_unloaded_set(const Klass* k); static int64_t event_class_count(); static bool is_unloaded(traceid klass_id, bool previous_epoch = false); static void clear(); diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp index c791a05f8181..e9e6a3968f5d 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -340,12 +340,12 @@ inline traceid JfrSymbolTable::Impl::add(const Symbol* sym) { return _symbols->lookup_put(sym->identity_hash(), sym)->id(); } -traceid JfrSymbolTable::Impl::add(const char* str) { +inline traceid JfrSymbolTable::Impl::add(const char* str) { assert(str != nullptr, "invariant"); return _strings->lookup_put(string_hash(str), str)->id(); } -inline traceid JfrSymbolTable::add(const Symbol* sym) { +traceid JfrSymbolTable::add(const Symbol* sym) { return this_epoch_table()->add(sym); } diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp index dc2908e8a811..ced01cfaa48a 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,31 +81,50 @@ int JfrFilterClassClosure::number_of_classes() const { return _classes_to_modify->number_of_entries(); } -void JfrFilterClassClosure::iterate_all_classes(GrowableArray* instrumented_klasses) { +void JfrFilterClassClosure::add(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert(ik != nullptr, "invariant"); + assert(ik->is_loader_alive(), "invariant"); + assert(JfrTraceId::has_sticky_bit(ik), "invariant"); + const traceid klass_id = JfrTraceId::load_raw(ik); + assert(!_classes_to_modify->contains(klass_id), "invariant"); + jclass mirror = mirror_as_local_jni_handle(ik, _thread); + _classes_to_modify->put(klass_id, mirror); +} + +bool JfrFilterClassClosure::do_entry(const traceid& id, const InstanceKlass*& ik) { + if (JfrKlassUnloading::is_unloaded(id, true)) { + // Returning true removes the unloaded entry from the placeholder table. + return true; + } + assert(!ik->is_loaded(), "invariant"); + add(ik); + return false; +} + +void JfrFilterClassClosure::iterate_all_classes(GrowableArray* instrumented_klasses, JfrPlaceholderTable* table) { assert(instrumented_klasses != nullptr, "invariant"); + assert(table != nullptr, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); // First we process the instrumented_klasses list. The fact that a klass is on that list implies // it matched _some_ previous filter, but we don't know which one. The nice thing is we don't need to know, // because a klass has the STICKY_BIT set for those methods that matched _some_ previous filter. - // We, therefore, put these klasses directly into the classes_to_modify set. We also need to do this - // because some klasses on the instrumented_klasses list may not have reached the point of add_to_hierarchy yet. - // For those klasses, the ClassLoaderDataGraph iterator would not deliver them on iteration. - + // We, therefore, put these klasses directly into the classes_to_modify set. if (instrumented_klasses->is_nonempty()) { for (int i = 0; i < instrumented_klasses->length(); ++i) { if (JfrKlassUnloading::is_unloaded(instrumented_klasses->at(i).trace_id())) { continue; } - const InstanceKlass* const ik = instrumented_klasses->at(i).instance_klass(); - assert(ik != nullptr, "invariant"); - assert(ik->is_loader_alive(), "invariant"); - assert(JfrTraceId::has_sticky_bit(ik), "invariant"); - const traceid klass_id = JfrTraceId::load_raw(ik); - assert(!_classes_to_modify->contains(klass_id), "invariant"); - jclass mirror = mirror_as_local_jni_handle(ik, _thread); - _classes_to_modify->put(klass_id, mirror); + add(instrumented_klasses->at(i).instance_klass()); } } + // We do the same also for the placeholder table because the classes contained + // have not reached the add_to_hierarchy point yet; the ClassLoaderDataGraph iterator + // would not deliver them on iteration. + if (table->number_of_entries() > 0) { + table->unlink(this); + } + ClassLoaderDataGraph::loaded_classes_do_keepalive(this); } diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp index 2febb43ce3ad..593c40be8997 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "jni.h" #include "memory/iterator.hpp" +class InstanceKlass; class JavaThread; class JfrFilter; class Klass; @@ -54,6 +55,13 @@ typedef ResizeableHashTable ClosureSet; +typedef ResizeableHashTable JfrPlaceholderTable; + // // Class that collects classes that should be retransformed, // either for adding instrumentation by matching the current @@ -66,14 +74,16 @@ class JfrFilterClassClosure : public KlassClosure { JavaThread* const _thread; bool match(const InstanceKlass* klass) const; + void add(const InstanceKlass* ik); void do_klass(Klass* k); public: JfrFilterClassClosure(JavaThread* thread); - void iterate_all_classes(GrowableArray* instrumented_klasses); + void iterate_all_classes(GrowableArray* instrumented_klasses, JfrPlaceholderTable* table); // Returned set is Resource allocated. ClosureSet* to_modify() const; int number_of_classes() const; + bool do_entry(const traceid& id, const InstanceKlass*& ik); }; #endif // SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.cpp index e094dc973150..90b81c760380 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.cpp @@ -57,6 +57,55 @@ ModuleEntry* JfrMethodTracer::_jdk_jfr_module = nullptr; GrowableArray* JfrMethodTracer::_instrumented_classes = nullptr; GrowableArray* JfrMethodTracer::_timing_entries = nullptr; +constexpr static unsigned int JFR_PLACEHOLDER_TABLE_SIZE = 1009; +constexpr static unsigned int MAX_JFR_PLACEHOLDER_TABLE_SIZE = 0x3fffffff; + +static JfrPlaceholderTable* _placeholder_table = nullptr; // Guarded by ClassLoaderDataGraph_lock + +static JfrPlaceholderTable* placeholder_table() { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + if (_placeholder_table == nullptr) { + _placeholder_table = new (mtTracing) JfrPlaceholderTable(JFR_PLACEHOLDER_TABLE_SIZE, MAX_JFR_PLACEHOLDER_TABLE_SIZE); + } + return _placeholder_table; +} + +class JfrPlaceholderTableCleaner : StackObj { + public: + bool do_entry(const traceid& id, const InstanceKlass*& ik) { + // Returning true removes the unloaded entry from the placeholder table. + return JfrKlassUnloading::is_unloaded(id, true); + } +}; + +static void clean_unloaded_placeholders() { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + if (placeholder_table()->number_of_entries() > 0) { + JfrPlaceholderTableCleaner cleaner; + placeholder_table()->unlink(&cleaner); + } +} + +/* + * Since the InstanceKlass* is not yet officially loaded, we need to stage the registration via a placeholder table. + * Iff the InstanceKlass* manages to pass through the class loading pipeline, and become selected for definition, + * we will get a callback to complete the registration process and put it onto the instrumented classes list. + * Only at that point is it safe to enqueue the ik for tagging purposes. + * Since these classes are in the process of loading, they have not yet registered with any JVM support structure + * (e.g., add_to_hierarchy or a dictionary).Therefore, this table is the only means of reaching these classes, + * which is necessary should a new filter be installed. + */ +static void register_placeholder(const InstanceKlass* ik, const JfrMethodProcessor& mp) { + assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invariant"); + assert(!ik->is_scratch_class(), "invariant"); + JfrTraceTagging::tag_preload_sticky(ik); + MutexLocker lock(ClassLoaderDataGraph_lock); + JfrTraceTagging::tag_sticky(ik, mp); + assert(!placeholder_table()->contains(JfrTraceId::load_raw(ik)), "invariant"); + placeholder_table()->put(JfrTraceId::load_raw(ik), ik); +} + // Quick and unlocked check to see if the Method Tracer has been activated. // This is flipped to not null the first time a filter is set and will stay non-null forever. bool JfrMethodTracer::in_use() { @@ -84,7 +133,7 @@ jlongArray JfrMethodTracer::set_filters(JNIEnv* env, jobjectArray classes, jobje JfrFilterClassClosure filter_class_closure(THREAD); { MutexLocker lock(ClassLoaderDataGraph_lock); - filter_class_closure.iterate_all_classes(instrumented_classes()); + filter_class_closure.iterate_all_classes(instrumented_classes(), placeholder_table()); ::clear(instrumented_classes()); } retransform(env, filter_class_closure, THREAD); @@ -128,10 +177,25 @@ void JfrMethodTracer::retransform(JNIEnv* env, const JfrFilterClassClosure& clas } } -static void handle_no_bytecode_result(const InstanceKlass* ik) { +#ifdef ASSERT +static bool in_list(const InstanceKlass* ik, const GrowableArray* list) { + assert(ik != nullptr, "invariant"); + assert(list != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + const JfrInstrumentedClass jic(JfrTraceId::load_raw(ik), ik, false); + return list->find(jic) != -1; +} +#endif + +void JfrMethodTracer::handle_no_bytecode_result(const InstanceKlass* ik) { assert(ik != nullptr, "invariant"); + MutexLocker lock(ClassLoaderDataGraph_lock); if (JfrTraceId::has_sticky_bit(ik)) { - MutexLocker lock(ClassLoaderDataGraph_lock); + if (!ik->is_loaded() && placeholder_table()->remove(JfrTraceId::load_raw(ik))) { + JfrTraceTagging::clear_sticky_for_placeholder(ik); + return; + } + JfrTraceTagging::clear_sticky_methods(ik); JfrTraceTagging::clear_sticky(ik); } } @@ -175,22 +239,28 @@ void JfrMethodTracer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& par JfrClassTransformer::rewrite_klass_pointer(ik, new_ik, parser, THREAD); // The ik is modified to point to new_ik here. mp.update_methods(existing_ik); existing_ik->module()->add_read(jdk_jfr_module()); + const bool is_loaded = existing_ik->is_loaded(); + MutexLocker lock(ClassLoaderDataGraph_lock); + if (!is_loaded && placeholder_table()->contains(JfrTraceId::load_raw(existing_ik))) { + assert(JfrTraceId::has_sticky_bit(existing_ik), "invariant"); + if (mp.has_timing() && !JfrTraceId::has_timing_bit(existing_ik)) { + JfrTraceId::set_timing_bit(existing_ik); + } + JfrTraceTagging::tag_sticky_for_placeholder_retransform_klass(existing_ik, ik, mp); + return; + } // By setting the sticky bit on the existng klass, we receive a callback into on_klass_redefinition (see below) // when our new methods are installed into the existing klass as part of retransformation / redefinition. // Only when we know our new methods have been installed can we add the klass to the instrumented list (done as part of callback). - JfrTraceTagging::tag_sticky_for_retransform_klass(existing_ik, ik, mp.methods(), mp.has_timing()); + JfrTraceTagging::tag_sticky_for_retransform_klass(existing_ik, ik, mp); return; } // Initial class load. JfrClassTransformer::cache_class_file_data(new_ik, clone, THREAD); // save the initial class file bytes (clone stream) JfrClassTransformer::rewrite_klass_pointer(ik, new_ik, parser, THREAD); // The ik is modified to point to new_ik here. mp.update_methods(ik); - // On initial class load the newly created klass can be installed into the instrumented class list directly. - add_instrumented_class(ik, mp.methods()); - if (mp.has_timing()) { - // After having installed the newly created klass into the list, perform an upcall to publish the associated TimedClass. - JfrUpcalls::publish_method_timers_for_klass(JfrTraceId::load_raw(ik), THREAD); - } + ik->module()->add_read(jdk_jfr_module()); + register_placeholder(ik, mp); } static inline void log_add(const InstanceKlass* ik) { @@ -235,31 +305,55 @@ void JfrMethodTracer::on_klass_redefinition(const InstanceKlass* ik, bool has_ti } } -#ifdef ASSERT -static bool in_instrumented_list(const InstanceKlass* ik, const GrowableArray* list) { - assert(ik != nullptr, "invariant"); - assert(list != nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - const JfrInstrumentedClass jic(JfrTraceId::load_raw(ik), ik, false); - return list->find(jic) != -1; +static void remove_from_placeholder_table(traceid id) { + assert(placeholder_table()->contains(id), "invariant"); + placeholder_table()->remove(id); + assert(!placeholder_table()->contains(id), "invariant"); } -#endif -void JfrMethodTracer::add_instrumented_class(InstanceKlass* ik, GrowableArray* methods) { +void JfrMethodTracer::add_instrumented_class(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); - assert(!ik->is_scratch_class(), "invariant"); - assert(methods->is_nonempty(), "invariant"); - ik->module()->add_read(jdk_jfr_module()); - MutexLocker lock(ClassLoaderDataGraph_lock); - assert(!in_instrumented_list(ik, instrumented_classes()), "invariant"); - JfrTraceTagging::tag_sticky(ik, methods); - const JfrInstrumentedClass jik(JfrTraceId::load_raw(ik), ik, false); - const int idx = instrumented_classes()->append(jik); - if (idx == 0) { - JfrTraceIdEpoch::set_method_tracer_tag_state(); + assert(!ik->is_loaded(), "invariant"); + assert(jt != nullptr, "invariant"); + const traceid id = JfrTraceId::load_raw(ik); + bool has_timing = false; + { + MutexLocker lock(ClassLoaderDataGraph_lock); + if (!JfrTraceId::has_sticky_bit(ik)) { + // A filter retransform removed the sticky bit from the ik + // and the corresponding entry in the placeholder table. + assert(!JfrTraceId::has_timing_bit(ik), "invariant"); + assert(!placeholder_table()->contains(id), "invariant"); + return; + } + remove_from_placeholder_table(id); + has_timing = JfrTraceId::has_timing_bit(ik); + if (has_timing) { + JfrTraceId::clear_timing_bit(ik); + } + JfrTraceTagging::enqueue(ik); + assert(!in_list(ik, instrumented_classes()), "invariant"); + const JfrInstrumentedClass jic(id, ik, false); + const int idx = instrumented_classes()->append(jic); + if (idx == 0) { + JfrTraceIdEpoch::set_method_tracer_tag_state(); + } + assert(in_list(ik, instrumented_classes()), "invariant"); } - assert(in_instrumented_list(ik, instrumented_classes()), "invariant"); log_add(ik); + if (has_timing) { + JfrUpcalls::publish_method_timers_for_klass(id, jt); + } +} + +void JfrMethodTracer::on_definition(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(JfrTraceId::has_preload_sticky_bit(ik), "invariant"); + assert(in_use(), "invariant"); + JfrTraceId::clear_preload_sticky_bit(ik); + // Last station before the ik is enqueued. The lifespan of preload bits ends here. + assert(0 == JfrTraceId::preload_bits(ik), "invariant"); + add_instrumented_class(ik, jt); } ModuleEntry* JfrMethodTracer::jdk_jfr_module() { @@ -338,8 +432,10 @@ void JfrMethodTracer::add_to_unloaded_set(const Klass* k) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); assert(JfrTraceId::has_sticky_bit(k), "invariant"); assert(_current_unloaded_class_ids != nullptr, "invariant"); - assert(_current_unloaded_class_ids->find(JfrTraceId::load_raw(k)) == -1, "invariant"); - _current_unloaded_class_ids->append(static_cast(JfrTraceId::load_raw(k))); + const jlong id = static_cast(JfrTraceId::load_raw(k)); + if (_current_unloaded_class_ids->find(id) == -1) { + _current_unloaded_class_ids->append(id); + } } // Invoked from JfrTypeSet after having finalized rotation. @@ -360,6 +456,8 @@ void JfrMethodTracer::trim_instrumented_classes(bool trim) { _instrumented_classes = trimmed_classes; } + clean_unloaded_placeholders(); + if (instrumented_classes()->is_nonempty()) { if (!JfrTraceIdEpoch::has_method_tracer_changed_tag_state()) { // Turn the tag state back on for next chunk. diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp index 8a214ab675b4..a106185304f0 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp @@ -53,7 +53,8 @@ class JfrMethodTracer: AllStatic { static ModuleEntry* jdk_jfr_module(); static void add_timing_entry(traceid klass_id); static void retransform(JNIEnv* env, const JfrFilterClassClosure& classes, TRAPS); - static void add_instrumented_class(InstanceKlass* ik, GrowableArray* methods); + static void add_instrumented_class(const InstanceKlass* ik, JavaThread* jt); + static void handle_no_bytecode_result(const InstanceKlass* ik); public: static bool in_use(); @@ -61,6 +62,7 @@ class JfrMethodTracer: AllStatic { static void add_to_unloaded_set(const Klass* k); static void trim_instrumented_classes(bool trim); static GrowableArray* instrumented_classes(); + static void on_definition(const InstanceKlass* ik, JavaThread* jt); static void on_klass_redefinition(const InstanceKlass* ik, bool has_timing); static void on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS); static jlongArray set_filters(JNIEnv* env, diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.cpp index dc70e70360f2..3e64a3a9d80f 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" +#include "jfr/support/methodtracer/jfrMethodProcessor.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" +#include "jfr/support/methodtracer/jfrTracedMethod.hpp" #include "jfr/support/methodtracer/jfrTraceTagging.hpp" #include "oops/instanceKlass.hpp" #include "oops/method.hpp" @@ -41,6 +43,7 @@ void JfrTraceTagging::tag_dynamic(const Method* method) { } void JfrTraceTagging::tag_sticky(const InstanceKlass* ik) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); JfrTraceId::set_sticky_bit(ik); } @@ -53,9 +56,16 @@ void JfrTraceTagging::tag_sticky(const Method* method) { JfrTraceId::set_sticky_bit(method); } -void JfrTraceTagging::tag_sticky(const GrowableArray* methods) { - assert(methods != nullptr, "invariant"); +void JfrTraceTagging::enqueue(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(JfrTraceId::has_sticky_bit(ik), "invariant"); + JfrTraceIdLoadBarrier::enqueue(ik); +} + +void JfrTraceTagging::tag_sticky(const JfrMethodProcessor& mp) { + const GrowableArray* methods = mp.methods(); + assert(methods != nullptr, "invariant"); for (int i = 0; i < methods->length(); ++i) { const Method* const method = methods->at(i).method(); assert(method != nullptr, "invariant"); @@ -63,19 +73,48 @@ void JfrTraceTagging::tag_sticky(const GrowableArray* methods) } } -void JfrTraceTagging::tag_sticky(const InstanceKlass* ik, const GrowableArray* methods) { +void JfrTraceTagging::tag_sticky(const InstanceKlass* ik, const JfrMethodProcessor& mp) { assert(ik != nullptr, "invariant"); assert(!ik->is_scratch_class(), "invariant"); - assert(methods != nullptr, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - tag_sticky(methods); - tag_sticky_enqueue(ik); + tag_sticky(mp); + if (mp.has_timing()) { + JfrTraceId::set_timing_bit(ik); + } + tag_sticky(ik); } -void JfrTraceTagging::clear_sticky(const InstanceKlass* ik, bool dynamic_tag /* true */) { +void JfrTraceTagging::tag_preload_sticky(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invariant"); + JfrTraceId::set_preload_sticky_bit(ik); +} + +void JfrTraceTagging::clear_sticky_for_placeholder(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + assert(!ik->is_loaded(), "invariant"); + assert(JfrTraceId::has_sticky_bit(ik), "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + if (JfrTraceId::has_timing_bit(ik)) { + JfrTraceId::clear_timing_bit(ik); + } + const Array* const methods = ik->methods(); + assert(methods != nullptr, "invariant"); + const int length = methods->length(); + for (int i = 0; i < length; ++i) { + const Method* const m = methods->at(i); + if (JfrTraceId::has_sticky_bit(m)) { + JfrTraceId::clear_sticky_bit(m); + } + } + JfrTraceId::clear_sticky_bit(ik); +} + +void JfrTraceTagging::clear_sticky_methods(const InstanceKlass* ik, bool dynamic_tag /* true */) { assert(ik != nullptr, "invariant"); assert(!ik->is_scratch_class(), "invariant"); assert(JfrTraceId::has_sticky_bit(ik), "invariant"); + assert(!ik->is_loaded() || dynamic_tag, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); const Array* const methods = ik->methods(); @@ -90,28 +129,49 @@ void JfrTraceTagging::clear_sticky(const InstanceKlass* ik, bool dynamic_tag /* JfrTraceId::clear_sticky_bit(m); } } +} + +void JfrTraceTagging::clear_sticky(const InstanceKlass* ik, bool dynamic_tag /* true */) { + assert(ik != nullptr, "invariant"); + assert(!ik->is_scratch_class(), "invariant"); + assert(JfrTraceId::has_sticky_bit(ik), "invariant"); + assert(!ik->is_loaded() || dynamic_tag, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); if (dynamic_tag) { tag_dynamic(ik); } JfrTraceId::clear_sticky_bit(ik); } -void JfrTraceTagging::tag_sticky_for_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const GrowableArray* methods, bool timing) { +void JfrTraceTagging::tag_sticky_for_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const JfrMethodProcessor& mp) { assert(existing_klass != nullptr, "invariant"); + assert(existing_klass->is_loaded(), "invariant"); assert(scratch_klass != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); // The scratch class has not yet received its official status. // assert(scratch_klass->is_scratch_class(), "invariant"); - if (timing) { - // Can be done outside lock because it is a scratch klass. - // Visibility guaranteed by upcoming safepoint. + if (mp.has_timing()) { JfrTraceId::set_timing_bit(scratch_klass); } - MutexLocker lock(ClassLoaderDataGraph_lock); if (JfrTraceId::has_sticky_bit(existing_klass)) { - clear_sticky(existing_klass); + clear_sticky_methods(existing_klass); + tag_sticky(mp); + enqueue(existing_klass); + return; } - tag_sticky(methods); - tag_sticky(existing_klass); + tag_sticky(mp); + tag_sticky_enqueue(existing_klass); +} + +void JfrTraceTagging::tag_sticky_for_placeholder_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const JfrMethodProcessor& mp) { + assert(existing_klass != nullptr, "invariant"); + assert(!existing_klass->is_loaded(), "invariant"); + assert(scratch_klass != nullptr, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(JfrTraceId::has_sticky_bit(existing_klass), "invariant"); + // No dynamic tag or enqueuing because the existing class has not been loaded yet. + clear_sticky_methods(existing_klass, false); + tag_sticky(mp); } void JfrTraceTagging::on_klass_redefinition(const InstanceKlass* ik, const InstanceKlass* scratch_klass) { @@ -121,11 +181,6 @@ void JfrTraceTagging::on_klass_redefinition(const InstanceKlass* ik, const Insta assert(scratch_klass->is_scratch_class(), "invariant"); assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - const bool klass_has_sticky_bit = JfrTraceId::has_sticky_bit(ik); - if (klass_has_sticky_bit) { - JfrTraceIdLoadBarrier::enqueue(ik); - } - const Array* new_methods = ik->methods(); assert(new_methods != nullptr, "invariant"); @@ -164,8 +219,9 @@ void JfrTraceTagging::on_klass_redefinition(const InstanceKlass* ik, const Insta // A retransformed/redefined klass carrying the sticky bit // needs additional processing by the JfrMethodTracer subsystem. - if (klass_has_sticky_bit) { + if (JfrTraceId::has_sticky_bit(ik)) { assert(JfrMethodTracer::in_use(), "invariant"); + enqueue(ik); JfrMethodTracer::on_klass_redefinition(ik, JfrTraceId::has_timing_bit(scratch_klass)); } } diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.hpp index 38ead4d0fed4..293f9cf1ed91 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrTraceTagging.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,13 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRTRACETAGGING_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRTRACETAGGING_HPP -#include "jfr/support/methodtracer/jfrTracedMethod.hpp" #include "memory/allStatic.hpp" class InstanceKlass; +class JavaThread; +class JfrMethodProcessor; class Method; -template class GrowableArray; - // // Class responsible for setting setting sticky, epoch, and timing bits. // @@ -42,13 +41,18 @@ class JfrTraceTagging : AllStatic { static void tag_dynamic(const Method* method); static void tag_sticky(const InstanceKlass* ik); static void tag_sticky(const Method* method); - static void tag_sticky(const GrowableArray* methods); + static void tag_sticky(const JfrMethodProcessor& mp); static void tag_sticky_enqueue(const InstanceKlass* ik); public: static void clear_sticky(const InstanceKlass* ik, bool dynamic_tag = true); - static void tag_sticky(const InstanceKlass* ik, const GrowableArray* methods); - static void tag_sticky_for_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const GrowableArray* methods, bool timing); + static void clear_sticky_methods(const InstanceKlass* ik, bool dynamic_tag = true); + static void clear_sticky_for_placeholder(const InstanceKlass* ik); + static void tag_sticky(const InstanceKlass* ik, const JfrMethodProcessor& mp); + static void tag_sticky_for_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const JfrMethodProcessor& mp); + static void tag_sticky_for_placeholder_retransform_klass(const InstanceKlass* existing_klass, const InstanceKlass* scratch_klass, const JfrMethodProcessor& mp); static void on_klass_redefinition(const InstanceKlass* ik, const InstanceKlass* scratch_klass); + static void enqueue(const InstanceKlass* ik); + static void tag_preload_sticky(const InstanceKlass* ik); }; #endif /* SHARE_JFR_SUPPORT_METHODTRACER_JFRTRACETAGGING_HPP */ diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index d13ae7117f39..b99fff3da28f 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -841,6 +841,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec assert(is_klass(), "ensure C++ vtable is restored"); assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); + JFR_ONLY(Jfr::on_restoration(this, THREAD);) if (log_is_enabled(Trace, aot, unshareable)) { ResourceMark rm(THREAD); oop class_loader = loader_data->class_loader(); @@ -859,8 +860,6 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec // (same order as class file parsing) loader_data->add_class(this); - JFR_ONLY(Jfr::on_restoration(this, THREAD);) - Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; Klass* k = this; diff --git a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEventWithViolatedLoadingConstraints.java b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEventWithViolatedLoadingConstraints.java new file mode 100644 index 000000000000..d588f7b6bbd1 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEventWithViolatedLoadingConstraints.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.runtime; + +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Path; +import java.util.List; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedClassLoader; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.jfr.TestClassLoader; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.event.runtime.TestClassDefineEventWithViolatedLoadingConstraints + */ + +public class TestClassDefineEventWithViolatedLoadingConstraints { + private final static String EVENT_NAME = EventNames.ClassDefine; + private final static String CLASS_NAME = TestClassDefineEventWithViolatedLoadingConstraints.class.getName(); + private final static String DEFINED_CLASS_NAME = CLASS_NAME + "$DuplicateDefinition"; + private final static String FAKE_SOURCE_PATH = "/my/fake/synthetic/classloading/source.jar"; + + static class DuplicateDefinition { } + + static class DuplicateDefinitionClassLoader extends ClassLoader { + DuplicateDefinitionClassLoader() { + super(null); + } + + Class define(byte[] bytes, String classname) throws Exception { + CodeSource cs = null; + try { + Path fakeJar = Path.of("my", "fake", "synthetic", "classloading", "source.jar"); + cs = new CodeSource(fakeJar.toUri().toURL(), (CodeSigner[]) null); + } catch (MalformedURLException ex) { + throw ex; + } + return defineClass(classname, bytes, 0, bytes.length, new ProtectionDomain(cs, null)); + } + } + + private static byte[] readClassBytes(Class clazz) throws IOException { + String resource = clazz.getName().replace('.', '/') + ".class"; + ClassLoader loader = clazz.getClassLoader(); + if (loader != null) { + InputStream in = loader.getResourceAsStream(resource); + if (in == null) { + throw new RuntimeException("Could not find " + clazz.getName()); + } + return in.readAllBytes(); + } + return null; + } + + public static void main(String[] args) throws Exception { + try (Recording recording = new Recording()) { + recording.enable(EVENT_NAME); + recording.start(); + byte[] duplicateDefBytes = readClassBytes(DuplicateDefinition.class); + DuplicateDefinitionClassLoader loader = new DuplicateDefinitionClassLoader(); + + // First class definition is fine and should result in a jdk.ClassDefine event. + loader.define(duplicateDefBytes, DEFINED_CLASS_NAME); + + try { + // Intentionally violate a class loading constraint by defining the same class + // again with the same class loader. This should throw a java.lang.LinkageError, + // and we should NOT get a jdk.ClassDefine event for this failed attempt. + // + // Most importantly, the JVM should NOT assert or crash as a consequence of JFR + // tagging and enqueuing an InstanceKlass that violates loading constraints. + // Because such an InstanceKlass is immediately put on the class_loader_data's deallocation list, + // it is not registered with a JFR unload set. + // + // Having such an InstanceKlass enqueued is therefore a broken invariant. + loader.define(duplicateDefBytes, DEFINED_CLASS_NAME); + throw new RuntimeException("Expected LinkageError not thrown"); + } catch (LinkageError e) { + // as expected + } finally { + recording.stop(); + } + + validate(recording); + } + } + + private static void validate(Recording recording) throws Exception { + List events = Events.fromRecording(recording); + int numberOfDuplicateDefinitionClassDefinedEvents = 0; + for (RecordedEvent event : events) { + System.out.println(event); + RecordedClassLoader definingClassLoader = event.getValue("definingClassLoader"); + if (definingClassLoader == null) { + continue; + } + RecordedClass classLoader = definingClassLoader.getType(); + if (classLoader == null) { + Asserts.assertTrue("bootstrap".equals(definingClassLoader.getName()), "not the bootstrap class loader?"); + continue; + } + if (DuplicateDefinitionClassLoader.class.getName().equals(classLoader.getName())) { + RecordedClass definedClass = event.getValue("definedClass"); + Asserts.assertNotNull(definedClass, "Defined Class should not be null"); + if (DEFINED_CLASS_NAME.equals(definedClass.getName())) { + Asserts.assertTrue(event.getString("source").startsWith("file://")); + Asserts.assertTrue(event.getString("source").endsWith(FAKE_SOURCE_PATH)); + numberOfDuplicateDefinitionClassDefinedEvents++; + } + } + } + Asserts.assertEquals(1, numberOfDuplicateDefinitionClassDefinedEvents, + "Wrong number of class define event for " + DEFINED_CLASS_NAME + ". Expected 1, got " + numberOfDuplicateDefinitionClassDefinedEvents); + } +} From 108dbeb632833c6588a3d68f327342b3bb318d7d Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Tue, 1 Sep 2026 15:14:01 +0000 Subject: [PATCH 174/223] 8390159: [ARM32] Native ARM32 build hangs in COMPILE_CREATE_SYMBOLS Reviewed-by: snazarki, iklam, thartmann, erikj, marchof --- make/autoconf/jdk-options.m4 | 13 +++++++++++-- src/hotspot/cpu/arm/jniFastGetField_arm.cpp | 6 ++++-- src/hotspot/share/c1/c1_Compilation.hpp | 5 ++++- src/hotspot/share/c1/c1_GraphBuilder.cpp | 2 +- src/hotspot/share/c1/c1_GraphBuilder.hpp | 1 + src/hotspot/share/cds/archiveUtils.cpp | 6 +++++- src/hotspot/share/oops/methodData.cpp | 8 ++++++++ src/hotspot/share/oops/methodData.hpp | 2 ++ src/hotspot/share/oops/symbol.hpp | 3 ++- 9 files changed, 38 insertions(+), 8 deletions(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 9abc849f0080..aaac824ecddb 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -829,9 +829,18 @@ AC_DEFUN([JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE_NOCOOPS], AC_DEFUN([JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE_PREVIEW], [ - UTIL_ARG_ENABLE(NAME: cds-archive-preview, DEFAULT: true, RESULT: BUILD_CDS_ARCHIVE_PREVIEW, + UTIL_ARG_ENABLE(NAME: cds-archive-preview, DEFAULT: auto, RESULT: BUILD_CDS_ARCHIVE_PREVIEW, DESC: [enable generation of preview CDS archives (requires --enable-cds-archive)], - CHECKING_MSG: [if default CDS archives for preview should be generated]) + CHECKING_MSG: [if default CDS archives for preview should be generated], + CHECK_AVAILABLE: [ + AC_MSG_CHECKING([if value objects are supported]) + if test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no (64-bit only)]) + AVAILABLE=false + fi + ]) AC_SUBST(BUILD_CDS_ARCHIVE_PREVIEW) ]) diff --git a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp index 301f54a0070a..fc7e439effa2 100644 --- a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp +++ b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp @@ -26,9 +26,11 @@ #include "asm/macroAssembler.hpp" #include "code/codeBlob.hpp" #include "memory/resourceArea.hpp" +#include "oops/instanceKlass.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" #include "prims/jvmtiExport.hpp" +#include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.hpp" #include "runtime/safepoint.hpp" @@ -138,10 +140,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { #endif // !__ABI_HARD__ ) { // Only ldr and ldrb support embedded shift, other loads do not - __ add(Robj, Robj, AsmOperand(R2, lsr, 2)); + __ add(Robj, Robj, AsmOperand(R2, lsr, jfieldIDWorkaround::offset_shift)); field_addr = Address(Robj); } else { - field_addr = Address(Robj, R2, lsr, 2); + field_addr = Address(Robj, R2, lsr, jfieldIDWorkaround::offset_shift); } assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp index 9779b3330b9a..605d3e4c353b 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -258,7 +258,10 @@ class Compilation: public StackObj { } bool profile_array_accesses() { return env()->comp_level() == CompLevel_full_profile && - C1UpdateMethodData; + C1UpdateMethodData && MethodData::profile_array_accesses(); + } + bool profile_acmp() { + return is_profiling() && profile_branches() && MethodData::profile_acmp(); } // will compilation make optimistic assumptions that might lead to diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 115751b129a1..a60a7619f208 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1390,7 +1390,7 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta } } if ((stream()->cur_bc() == Bytecodes::_if_acmpeq || stream()->cur_bc() == Bytecodes::_if_acmpne) && - is_profiling() && profile_branches()) { + profile_acmp()) { compilation()->set_would_profile(true); append(new ProfileACmpTypes(method(), bci(), x, y)); } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.hpp b/src/hotspot/share/c1/c1_GraphBuilder.hpp index 2a8517905013..5fcde20964ba 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.hpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.hpp @@ -430,6 +430,7 @@ class GraphBuilder { bool profile_arguments() { return _compilation->profile_arguments(); } bool profile_return() { return _compilation->profile_return(); } bool profile_array_accesses(){ return _compilation->profile_array_accesses();} + bool profile_acmp() { return _compilation->profile_acmp(); } Values* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver); Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver); diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 7261fb1a5c6c..af0ae2c7a44a 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -389,7 +389,11 @@ char* DumpRegion::allocate_metaspace_obj(size_t num_bytes, address src, Metaspac assert(read_only == false, "only gaps in RW region are reusable"); char* gap_bottom = top(); char* gap_top = align_up(gap_bottom + RuntimeClassInfoPtrSize, alignment) - RuntimeClassInfoPtrSize; - size_t gap_bytes = _gap_tree.add_gap(gap_bottom, gap_top); + size_t gap_bytes = pointer_delta(gap_top, gap_bottom, 1); + // A gap smaller than an allocation unit can never be reused + if (gap_bytes >= SharedSpaceObjectAlignment) { + _gap_tree.add_gap(gap_bottom, gap_top); + } allocate(gap_bytes); } diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index b871fd87831f..6e35f05c9ce5 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1703,6 +1703,14 @@ bool MethodData::profile_parameters_jsr292_only() { return profile_parameters_flag() == type_profile_jsr292; } +bool MethodData::profile_array_accesses() { + return COMPILER2_PRESENT(UseArrayLoadStoreProfile ||) TypeProfileLevel > 0; +} + +bool MethodData::profile_acmp() { + return COMPILER2_PRESENT(UseACmpProfile ||) TypeProfileLevel > 0; +} + bool MethodData::profile_all_parameters() { return profile_parameters_flag() == type_profile_all; } diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index aa8c961b7c90..02072262b16b 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -2724,6 +2724,8 @@ class MethodData : public Metadata { static bool profile_arguments_jsr292_only(); static bool profile_return(); static bool profile_parameters(); + static bool profile_array_accesses(); + static bool profile_acmp(); static bool profile_return_jsr292_only(); void clean_method_data(bool always_clean); diff --git a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp index 2fc664dfab2d..1acca970039c 100644 --- a/src/hotspot/share/oops/symbol.hpp +++ b/src/hotspot/share/oops/symbol.hpp @@ -101,7 +101,8 @@ class ClassLoaderData; #define PERM_REFCOUNT 0xffff #endif -class Symbol : public MetaspaceObj { +// VerificationType::TypeMask == 0x7 demands 8-byte aligned Symbol* +class alignas(8) Symbol : public MetaspaceObj { friend class VMStructs; friend class SymbolTable; friend class vmSymbols; From d4798611e642995fbb3cba1d5e1fa5c9dab6cdda Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Tue, 1 Sep 2026 15:20:43 +0000 Subject: [PATCH 175/223] 8387949: Implementation of PEM Encodings of Cryptographic Objects Reviewed-by: mullan, weijun --- .../java/security/BinaryEncodable.java | 19 ++++++++------- .../share/classes/java/security/PEM.java | 11 +-------- .../classes/java/security/PEMDecoder.java | 15 +----------- .../classes/java/security/PEMEncoder.java | 9 +------- .../classes/javax/crypto/CryptoException.java | 5 +--- .../javax/crypto/EncryptedPrivateKeyInfo.java | 23 ++++++------------- .../jdk/internal/javac/PreviewFeature.java | 3 --- .../KeyStore/PKCS12/WriteP12Test.java | 3 +-- .../security/KeyStore/TestKeyStoreBasic.java | 1 - .../jdk/java/security/PEM/PEMDecoderTest.java | 1 - .../jdk/java/security/PEM/PEMEncoderTest.java | 1 - .../java/security/PEM/PEMMultiThreadTest.java | 3 +-- .../cert/CertPathBuilder/NoExtensions.java | 3 +-- .../selfIssued/DisableRevocation.java | 1 - .../selfIssued/KeyUsageMatters.java | 1 - .../selfIssued/StatusLoopDependency.java | 1 - .../CertPathValidator/OCSP/FailoverToCRL.java | 1 - .../indirectCRL/CircularCRLOneLevel.java | 1 - .../CircularCRLOneLevelRevoked.java | 1 - .../indirectCRL/CircularCRLTwoLevel.java | 1 - .../CircularCRLTwoLevelRevoked.java | 3 +-- .../NameConstraintsWithRID.java | 3 +-- .../NameConstraintsWithUnexpectedRID.java | 3 +-- .../NameConstraintsWithoutRID.java | 3 +-- .../trustAnchor/ValWithAnchorByName.java | 3 +-- .../EncryptedPrivateKeyInfo/Encrypt.java | 1 - .../EncryptedPrivateKeyInfo/GetKey.java | 1 - .../EncryptedPrivateKeyInfo/GetKeyPair.java | 1 - .../ssl/ServerName/SSLSocketSNISensitive.java | 3 +-- test/jdk/javax/net/ssl/TLSCommon/TLSTest.java | 3 +-- test/jdk/sun/security/internal/CheckIBE.java | 1 - .../sun/security/internal/ExhaustiveBE.java | 1 - .../DisabledAlgorithms/CPBuilder.java | 1 - .../DisabledAlgorithms/CPBuilderWithMD5.java | 1 - .../CPValidatorEndEntity.java | 3 +-- .../CPValidatorIntermediate.java | 3 +-- .../CPValidatorTrustAnchor.java | 3 +-- .../sun/security/rsa/InvalidBitString.java | 3 +-- .../security/rsa/pss/PSSKeyCompatibility.java | 1 - .../ssl/ClientHandshaker/RSAExport.java | 3 +-- .../BasicConstraints.java | 3 +-- .../X509TrustManagerImpl/ComodoHacker.java | 3 +-- .../X509TrustManagerImpl/PKIXExtendedTM.java | 1 - .../SunX509ExtendedTM.java | 1 - .../validator/PKIXValAndRevCheckTests.java | 1 - .../sun/security/x509/X509CRLImpl/Verify.java | 3 +-- 46 files changed, 38 insertions(+), 122 deletions(-) diff --git a/src/java.base/share/classes/java/security/BinaryEncodable.java b/src/java.base/share/classes/java/security/BinaryEncodable.java index a1713c413ba1..011c511f0434 100644 --- a/src/java.base/share/classes/java/security/BinaryEncodable.java +++ b/src/java.base/share/classes/java/security/BinaryEncodable.java @@ -31,27 +31,27 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; -import jdk.internal.javac.PreviewFeature; import sun.security.internal.InternalBinaryEncodable; - /** - * This interface identifies the cryptographic objects that can be converted - * to and from binary data, and thereby encoded and decoded as PEM text. + * This interface identifies cryptographic objects that can be converted to + * and from standardized binary representations. * *

      The APIs for cryptographic objects such as public keys, private keys, * certificates, and certificate revocation lists all provide the means to * convert their instances to and from standardized binary representations. * Other kinds of cryptographic objects, such as certificate requests, have * no corresponding API but can still be expressed as standardized binary - * representations. The {@code BinaryEncodable} interface allows the - * {@link PEMEncoder} and {@link PEMDecoder} classes to operate uniformly on - * binary representations of key or certificate material. + * representations. The {@code BinaryEncodable} interface allows APIs that + * operate on standardized binary representations, such as {@link PEMEncoder} + * and {@link PEMDecoder}, to process all kinds of cryptographic objects + * uniformly. * *

      The permitted subtype {@code PEM} is notable for supporting the encoding * and decoding of PEM text that represents cryptographic objects for which no * API exists. In future releases, other permitted subtypes may be added to - * support the encoding and decoding of such cryptographic objects. + * support the encoding and decoding of additional kinds of cryptographic + * objects as standardized binary representations. * *

      The list of permitted subtypes shown after {@code permits} is not * exhaustive. This means if application code switches over a @@ -71,10 +71,9 @@ * @see X509CRL * @see PEM * - * @since 27 + * @since 28 */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public sealed interface BinaryEncodable permits AsymmetricKey, KeyPair, PKCS8EncodedKeySpec, X509EncodedKeySpec, EncryptedPrivateKeyInfo, X509Certificate, X509CRL, PEM, InternalBinaryEncodable { diff --git a/src/java.base/share/classes/java/security/PEM.java b/src/java.base/share/classes/java/security/PEM.java index 421ae40b30f2..87aa857ff7ff 100644 --- a/src/java.base/share/classes/java/security/PEM.java +++ b/src/java.base/share/classes/java/security/PEM.java @@ -25,8 +25,6 @@ package java.security; -import jdk.internal.javac.PreviewFeature; - import jdk.internal.ref.CleanerFactory; import sun.security.util.KeyUtil; import sun.security.util.Pem; @@ -72,9 +70,8 @@ * @see PEMDecoder * @see PEMEncoder * - * @since 26 + * @since 28 */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public final class PEM implements BinaryEncodable { private final String type; @@ -133,8 +130,6 @@ public PEM(String type, String base64Content) { * @throws IllegalArgumentException if {@code type} contains PEM * encapsulation syntax * @throws NullPointerException if any parameter is {@code null} - * - * @since 27 */ public PEM(String type, byte[] base64Content, byte[] leadingData) { this(type, base64Content); @@ -153,8 +148,6 @@ public PEM(String type, byte[] base64Content, byte[] leadingData) { * @throws IllegalArgumentException if {@code type} contains PEM * encapsulation syntax * @throws NullPointerException if any parameter is {@code null} - * - * @since 27 */ public PEM(String type, byte[] base64Content) { Objects.requireNonNull(type, "type cannot be null"); @@ -198,8 +191,6 @@ public byte[] leadingData() { * Returns the Base64-encoded content. * * @return a newly-allocated byte array containing the Base64 content - * - * @since 27 */ public byte[] content() { try { diff --git a/src/java.base/share/classes/java/security/PEMDecoder.java b/src/java.base/share/classes/java/security/PEMDecoder.java index 8ebc83f93d10..dfd0a9d4094c 100644 --- a/src/java.base/share/classes/java/security/PEMDecoder.java +++ b/src/java.base/share/classes/java/security/PEMDecoder.java @@ -25,8 +25,6 @@ package java.security; -import jdk.internal.javac.PreviewFeature; - import jdk.internal.ref.CleanerFactory; import sun.security.pkcs.PKCS8Key; import sun.security.rsa.RSAPrivateCrtKeyImpl; @@ -147,9 +145,8 @@ * @spec https://www.rfc-editor.org/info/rfc7468 * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures * - * @since 25 + * @since 28 */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public final class PEMDecoder { private final Provider factory; private final PBEKeySpec keySpec; @@ -294,8 +291,6 @@ yield new KeyPair(getKeyFactory(algo). * @throws IllegalArgumentException if decoding fails or no PEM data is found * @throws NullPointerException if {@code str} is {@code null} * @throws CryptoException if an error occurs during decryption - * - * @since 27 */ public BinaryEncodable decode(String str) { Objects.requireNonNull(str); @@ -335,8 +330,6 @@ public BinaryEncodable decode(String str) { * @throws IllegalArgumentException if decoding fails * @throws NullPointerException if {@code InputStream} is {@code null} * @throws CryptoException if an error occurs during decryption - * - * @since 27 */ public BinaryEncodable decode(InputStream is) throws IOException { Objects.requireNonNull(is); @@ -379,8 +372,6 @@ public BinaryEncodable decode(InputStream is) throws IOException { * @throws ClassCastException if {@code tClass} does not represent the PEM type * @throws NullPointerException if any input values are {@code null} * @throws CryptoException if an error occurs during decryption - * - * @since 27 */ public S decode(String str, Class tClass) { Objects.requireNonNull(str); @@ -428,8 +419,6 @@ public S decode(String str, Class tClass) { * * @see #decode(InputStream) * @see #decode(String, Class) - * - * @since 27 */ public S decode(InputStream is, Class tClass) throws IOException { @@ -543,8 +532,6 @@ private CertificateFactory getCertFactory(String algorithm) { * @param provider the factory {@code Provider} * @return a new {@code PEMDecoder} instance configured with the {@code Provider} * @throws NullPointerException if {@code provider} is {@code null} - * - * @since 27 */ public PEMDecoder withFactoriesOf(Provider provider) { Objects.requireNonNull(provider); diff --git a/src/java.base/share/classes/java/security/PEMEncoder.java b/src/java.base/share/classes/java/security/PEMEncoder.java index 211b47008a5f..2066c3a3d987 100644 --- a/src/java.base/share/classes/java/security/PEMEncoder.java +++ b/src/java.base/share/classes/java/security/PEMEncoder.java @@ -25,8 +25,6 @@ package java.security; -import jdk.internal.javac.PreviewFeature; - import jdk.internal.ref.CleanerFactory; import sun.security.pkcs.PKCS8Key; import sun.security.util.KeyUtil; @@ -117,9 +115,8 @@ * @spec https://www.rfc-editor.org/info/rfc7468 * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures * - * @since 25 + * @since 28 */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public final class PEMEncoder { // Singleton instance of PEMEncoder @@ -169,8 +166,6 @@ public static PEMEncoder of() { * @throws NullPointerException if {@code be} is {@code null} * @throws CryptoException if an error occurs during encryption * @see #withEncryption(char[]) - * - * @since 27 */ public String encodeToString(BinaryEncodable be) { Objects.requireNonNull(be); @@ -196,8 +191,6 @@ public String encodeToString(BinaryEncodable be) { * @throws NullPointerException if {@code be} is {@code null} * @throws CryptoException if an error occurs during encryption * @see #withEncryption(char[]) - * - * @since 27 */ public byte[] encode(BinaryEncodable be) { return switch (be) { diff --git a/src/java.base/share/classes/javax/crypto/CryptoException.java b/src/java.base/share/classes/javax/crypto/CryptoException.java index 367417abf9dd..86ac616b9147 100644 --- a/src/java.base/share/classes/javax/crypto/CryptoException.java +++ b/src/java.base/share/classes/javax/crypto/CryptoException.java @@ -25,8 +25,6 @@ package javax.crypto; -import jdk.internal.javac.PreviewFeature; - /** * Thrown to indicate a cryptographic failure during processing. * @@ -38,9 +36,8 @@ *

      This exception is not intended to represent internal provider errors, * which should be reported using {@link java.security.ProviderException}. * - * @since 27 + * @since 28 */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public final class CryptoException extends RuntimeException { @java.io.Serial diff --git a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java index 632c81eab169..64eb2d79922d 100644 --- a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java @@ -25,8 +25,6 @@ package javax.crypto; -import jdk.internal.javac.PreviewFeature; - import sun.security.jca.JCAUtil; import sun.security.pkcs.PKCS8Key; import sun.security.util.*; @@ -368,9 +366,8 @@ private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey, * not supported by any provider, or if an error occurs during * encryption * - * @since 27 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public static EncryptedPrivateKeyInfo encrypt(BinaryEncodable be, char[] password, String algorithm, AlgorithmParameterSpec params, Provider provider) { @@ -411,9 +408,8 @@ public static EncryptedPrivateKeyInfo encrypt(BinaryEncodable be, * defines the default encryption algorithm. The {@code AlgorithmParameterSpec} * defaults are determined by the provider. * - * @since 27 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public static EncryptedPrivateKeyInfo encrypt(BinaryEncodable be, char[] password) { return encrypt(be, password, Pem.DEFAULT_ALGO, null, @@ -450,9 +446,8 @@ public static EncryptedPrivateKeyInfo encrypt(BinaryEncodable be, * {@code algorithm} or {@code params} are not supported by any * provider, or if an error occurs during encryption * - * @since 27 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public static EncryptedPrivateKeyInfo encrypt(BinaryEncodable be, Key encryptKey, String algorithm, AlgorithmParameterSpec params, Provider provider, SecureRandom random) { @@ -520,9 +515,8 @@ private static EncryptedPrivateKeyInfo encryptImpl(byte[] encoded, * @throws InvalidKeyException if an error occurs during parsing, * decryption, or key generation * - * @since 25 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public PrivateKey getKey(char[] password) throws NoSuchAlgorithmException, InvalidKeyException { Objects.requireNonNull(password, "a password must be specified"); @@ -548,9 +542,8 @@ public PrivateKey getKey(char[] password) * @throws InvalidKeyException if an error occurs during parsing, * decryption, or key generation * - * @since 27 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public PrivateKey getKey(Key decryptKey) throws NoSuchAlgorithmException, InvalidKeyException { Objects.requireNonNull(decryptKey,"a decryptKey must be specified"); @@ -576,9 +569,8 @@ public PrivateKey getKey(Key decryptKey) * @throws InvalidKeyException if the encoded data lacks a public key, or if * an error occurs during parsing, decryption, or key generation * - * @since 26 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public KeyPair getKeyPair(char[] password) throws NoSuchAlgorithmException, InvalidKeyException { Objects.requireNonNull(password, "a password must be specified"); @@ -614,9 +606,8 @@ public KeyPair getKeyPair(char[] password) * @throws InvalidKeyException if the encoded data lacks a public key, or if * an error occurs during parsing, decryption, or key generation * - * @since 27 + * @since 28 */ - @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public KeyPair getKeyPair(Key decryptKey) throws NoSuchAlgorithmException, InvalidKeyException { Objects.requireNonNull(decryptKey,"a decryptKey must be specified"); diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 280070e187aa..bc7b77110a84 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -77,9 +77,6 @@ public enum Feature { STRUCTURED_CONCURRENCY, @JEP(number = 531, title = "Lazy Constants", status = "Third Preview") LAZY_CONSTANTS, - @JEP(number=538, title="PEM Encodings of Cryptographic Objects", - status="Third Preview") - PEM_API, /** * Indicates a preview API exists to allow access to the environment * where all preview features of the current Java SE release are enabled. diff --git a/test/jdk/java/security/KeyStore/PKCS12/WriteP12Test.java b/test/jdk/java/security/KeyStore/PKCS12/WriteP12Test.java index 535cb8c8f4c5..56fdf4190c3f 100644 --- a/test/jdk/java/security/KeyStore/PKCS12/WriteP12Test.java +++ b/test/jdk/java/security/KeyStore/PKCS12/WriteP12Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,6 @@ * @summary Write different types p12 key store to Check the write related * APIs. * @run main WriteP12Test - * @enablePreview */ public class WriteP12Test { diff --git a/test/jdk/java/security/KeyStore/TestKeyStoreBasic.java b/test/jdk/java/security/KeyStore/TestKeyStoreBasic.java index e39793cf1b79..eda7d0f29d83 100644 --- a/test/jdk/java/security/KeyStore/TestKeyStoreBasic.java +++ b/test/jdk/java/security/KeyStore/TestKeyStoreBasic.java @@ -36,7 +36,6 @@ /* * @test * @bug 8048621 8133090 8167371 8236671 8374808 - * @enablePreview * @summary Test basic operations with keystores (jks, jceks, pkcs12) * @author Yu-Ching Valerie PENG */ diff --git a/test/jdk/java/security/PEM/PEMDecoderTest.java b/test/jdk/java/security/PEM/PEMDecoderTest.java index dc0fe18956d2..96fc2705c90f 100644 --- a/test/jdk/java/security/PEM/PEMDecoderTest.java +++ b/test/jdk/java/security/PEM/PEMDecoderTest.java @@ -30,7 +30,6 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * @summary Testing basic PEM API decoding - * @enablePreview */ import javax.crypto.EncryptedPrivateKeyInfo; diff --git a/test/jdk/java/security/PEM/PEMEncoderTest.java b/test/jdk/java/security/PEM/PEMEncoderTest.java index 4d205f2f9bf3..1b6abf8c011d 100644 --- a/test/jdk/java/security/PEM/PEMEncoderTest.java +++ b/test/jdk/java/security/PEM/PEMEncoderTest.java @@ -28,7 +28,6 @@ * @bug 8298420 * @library /test/lib * @summary Testing basic PEM API encoding - * @enablePreview * @modules java.base/sun.security.util * @run main PEMEncoderTest PBEWithHmacSHA256AndAES_128 * @run main/othervm -Djava.security.properties=${test.src}/java.security-anotherAlgo diff --git a/test/jdk/java/security/PEM/PEMMultiThreadTest.java b/test/jdk/java/security/PEM/PEMMultiThreadTest.java index f345a3c129dc..a22eae364637 100644 --- a/test/jdk/java/security/PEM/PEMMultiThreadTest.java +++ b/test/jdk/java/security/PEM/PEMMultiThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ * @bug 8298420 * @library /test/lib * @summary Testing PEM API is thread safe - * @enablePreview * @modules java.base/sun.security.util */ diff --git a/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java b/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java index e38d18dc9439..c1bfae338b3f 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java +++ b/test/jdk/java/security/cert/CertPathBuilder/NoExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 4519462 * @summary Verify Sun CertPathBuilder implementation handles certificates with no extensions - * @enablePreview */ import java.security.PEMDecoder; diff --git a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/DisableRevocation.java b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/DisableRevocation.java index 1f48b077aca5..7a5c1f47855a 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/DisableRevocation.java +++ b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/DisableRevocation.java @@ -36,7 +36,6 @@ * @run main/othervm DisableRevocation subca * @run main/othervm DisableRevocation subci * @run main/othervm DisableRevocation alice - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/KeyUsageMatters.java b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/KeyUsageMatters.java index fc49aa69f842..e3fa6ec796c2 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/KeyUsageMatters.java +++ b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/KeyUsageMatters.java @@ -32,7 +32,6 @@ * @bug 6852744 8133489 * @summary PIT b61: PKI test suite fails because self signed certificates * are being rejected - * @enablePreview * @modules java.base/sun.security.util * @run main/othervm -Djava.security.debug=certpath KeyUsageMatters subca * @run main/othervm -Djava.security.debug=certpath KeyUsageMatters subci diff --git a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java index 95b02811a202..bb7344fd9593 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java +++ b/test/jdk/java/security/cert/CertPathBuilder/selfIssued/StatusLoopDependency.java @@ -33,7 +33,6 @@ * @summary PIT b61: PKI test suite fails because self signed certificates * are being rejected * @modules java.base/sun.security.util - * @enablePreview * @run main/othervm StatusLoopDependency subca * @run main/othervm StatusLoopDependency subci * @run main/othervm StatusLoopDependency alice diff --git a/test/jdk/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java b/test/jdk/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java index 3bf801b8255c..25e4b7aa5650 100644 --- a/test/jdk/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java +++ b/test/jdk/java/security/cert/CertPathValidator/OCSP/FailoverToCRL.java @@ -32,7 +32,6 @@ * @bug 6383095 * @summary CRL revoked certificate failures masked by OCSP failures * @run main/othervm FailoverToCRL - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevel.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevel.java index 81b6a4d1351b..30918c176bb8 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevel.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevel.java @@ -33,7 +33,6 @@ * @bug 6720721 * @summary CRL check with circular depency support needed * @run main/othervm CircularCRLOneLevel - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevelRevoked.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevelRevoked.java index caedb27f823b..786ee2f17bfb 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevelRevoked.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLOneLevelRevoked.java @@ -33,7 +33,6 @@ * @bug 6720721 * @summary CRL check with circular depency support needed * @run main/othervm CircularCRLOneLevelRevoked - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java index 4a5d9fe409a1..1acf92dd770e 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevel.java @@ -32,7 +32,6 @@ * * @bug 6720721 * @summary CRL check with circular depency support needed - * @enablePreview * @run main/othervm CircularCRLTwoLevel * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java index 909b3e53a148..cad7b421d4b5 100644 --- a/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java +++ b/test/jdk/java/security/cert/CertPathValidator/indirectCRL/CircularCRLTwoLevelRevoked.java @@ -31,8 +31,7 @@ * @test * * @bug 6720721 - * @summary CRL check with circular depency support needed - * @enablePreview + * @summary CRL check with circular dependency support needed * @run main/othervm CircularCRLTwoLevelRevoked * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithRID.java b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithRID.java index d7dcfc6b6d53..a35223c43185 100644 --- a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithRID.java +++ b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithRID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * * @bug 6845286 * @summary Add regression test for name constraints - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithUnexpectedRID.java b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithUnexpectedRID.java index 333e9b19f300..00014f9be8ae 100644 --- a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithUnexpectedRID.java +++ b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithUnexpectedRID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * * @bug 6845286 * @summary Add regression test for name constraints - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithoutRID.java b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithoutRID.java index 63b4f921e0e0..82323d937762 100644 --- a/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithoutRID.java +++ b/test/jdk/java/security/cert/CertPathValidator/nameConstraints/NameConstraintsWithoutRID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * * @bug 6845286 * @summary Add regression test for name constraints - * @enablePreview * @author Xuelei Fan */ diff --git a/test/jdk/java/security/cert/CertPathValidator/trustAnchor/ValWithAnchorByName.java b/test/jdk/java/security/cert/CertPathValidator/trustAnchor/ValWithAnchorByName.java index 58d3c37975a7..309bdb4e9963 100644 --- a/test/jdk/java/security/cert/CertPathValidator/trustAnchor/ValWithAnchorByName.java +++ b/test/jdk/java/security/cert/CertPathValidator/trustAnchor/ValWithAnchorByName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * @bug 8132926 * @summary PKIXParameters built with public key form of TrustAnchor causes * NPE during cert path building/validation - * @enablePreview * @run main ValWithAnchorByName */ diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/Encrypt.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/Encrypt.java index 631410efb210..dbc70c12b6ef 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/Encrypt.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/Encrypt.java @@ -29,7 +29,6 @@ * @modules java.base/sun.security.util * @bug 8298420 * @summary Testing encryptKey - * @enablePreview */ import sun.security.util.Pem; diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKey.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKey.java index a4bfd4e47d60..0de72330860e 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKey.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKey.java @@ -27,7 +27,6 @@ * @test * @bug 8298420 * @summary Testing getKey - * @enablePreview */ import javax.crypto.EncryptedPrivateKeyInfo; diff --git a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeyPair.java b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeyPair.java index fd4df8366abb..4eaaf645c4f2 100644 --- a/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeyPair.java +++ b/test/jdk/javax/crypto/EncryptedPrivateKeyInfo/GetKeyPair.java @@ -28,7 +28,6 @@ * @bug 8360563 * @library /test/lib * @summary Testing getKeyPair using ML-KEM - * @enablePreview * @modules java.base/sun.security.util */ diff --git a/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java b/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java index fd1569b4eeaf..a1d1eae4d237 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLSocketSNISensitive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * @test * @bug 7068321 * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server - * @enablePreview * @run main/othervm SSLSocketSNISensitive PKIX www.example.com * @run main/othervm SSLSocketSNISensitive SunX509 www.example.com * @run main/othervm SSLSocketSNISensitive PKIX www.example.net diff --git a/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java b/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java index fc6369a2bbc7..5bb8548ec617 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java +++ b/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ /* * @test * @bug 8205111 - * @enablePreview * @summary Test TLS with different types of supported keys. * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_128_GCM_SHA256 * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256 diff --git a/test/jdk/sun/security/internal/CheckIBE.java b/test/jdk/sun/security/internal/CheckIBE.java index 802cd336ebc3..8e38c0d4ddcb 100644 --- a/test/jdk/sun/security/internal/CheckIBE.java +++ b/test/jdk/sun/security/internal/CheckIBE.java @@ -25,7 +25,6 @@ * @test * @bug 8383608 * @summary check that InternalBinaryEncodable exists - * @enablePreview * @modules java.base/sun.security.internal * @run main CheckIBE */ diff --git a/test/jdk/sun/security/internal/ExhaustiveBE.java b/test/jdk/sun/security/internal/ExhaustiveBE.java index 37222a0310ab..370ff58c28d8 100644 --- a/test/jdk/sun/security/internal/ExhaustiveBE.java +++ b/test/jdk/sun/security/internal/ExhaustiveBE.java @@ -25,7 +25,6 @@ * @test * @bug 8383608 * @summary verify switches over BinaryEncodable are not exhaustive - * @enablePreview * @compile/fail ExhaustiveBE.java */ diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java index 9c68ae138ef7..54d96a1f1338 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java @@ -29,7 +29,6 @@ * * @bug 6861062 * @summary Disable MD2 support - * @enablePreview * * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_1024 0 true * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_512 0 true diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java index cbdeb6609e42..2a008d4a34a2 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPBuilderWithMD5.java @@ -29,7 +29,6 @@ * * @bug 8030829 * @summary Add MD5 to jdk.certpath.disabledAlgorithms security property - * @enablePreview * * @run main/othervm CPBuilderWithMD5 trustAnchor_SHA1withRSA_1024 0 true * @run main/othervm CPBuilderWithMD5 trustAnchor_SHA1withRSA_512 0 true diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java index aa19bc2f0c83..4715f3aadf68 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @summary Disable MD2 support. * New CertPathValidatorException.BasicReason enum constant for * constrained algorithm. - * @enablePreview * @run main/othervm CPValidatorEndEntity * @author Xuelei Fan */ diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java index 72dff1694b1c..ca5132e63fd7 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @summary Disable MD2 support * new CertPathValidatorException.BasicReason enum constant for * constrained algorithm - * @enablePreview * @run main/othervm CPValidatorIntermediate * @author Xuelei Fan */ diff --git a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java index d74d712d8d74..80173d7e2b36 100644 --- a/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java +++ b/test/jdk/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @summary Disable MD2 support * new CertPathValidatorException.BasicReason enum constant for * constrained algorithm - * @enablePreview * @run main/othervm CPValidatorTrustAnchor * @author Xuelei Fan */ diff --git a/test/jdk/sun/security/rsa/InvalidBitString.java b/test/jdk/sun/security/rsa/InvalidBitString.java index 7f8408f35f0b..53fabc50bbb3 100644 --- a/test/jdk/sun/security/rsa/InvalidBitString.java +++ b/test/jdk/sun/security/rsa/InvalidBitString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ /* @test * @summary Validation of signatures succeed when it should fail - * @enablePreview * @bug 6896700 */ diff --git a/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java b/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java index 49ee7387f177..61701a686faa 100644 --- a/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java +++ b/test/jdk/sun/security/rsa/pss/PSSKeyCompatibility.java @@ -44,7 +44,6 @@ * @test * @bug 8242335 * @summary OpenSSL generated compatibility test with RSASSA-PSS Java. - * @enablePreview * @run main PSSKeyCompatibility */ diff --git a/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java b/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java index 26d5c69e2198..ffa4724f98c6 100644 --- a/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java +++ b/test/jdk/sun/security/ssl/ClientHandshaker/RSAExport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ /* * @test * @bug 6690018 - * @enablePreview * @summary RSAClientKeyExchange NullPointerException * @run main/othervm RSAExport */ diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java index 051c940b3b08..ddf27ab71b20 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * @bug 7166570 * @summary JSSE certificate validation has started to fail for * certificate chains - * @enablePreview * @run main/othervm BasicConstraints PKIX * @run main/othervm BasicConstraints SunX509 */ diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java index f1e5415e2c3b..974ac870e06a 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/ComodoHacker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 7123519 * @summary Problem with java/classes_security - * @enablePreview * @run main/othervm ComodoHacker PKIX * @run main/othervm ComodoHacker SunX509 */ diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java index 287dbcc2b025..e3422c4955c3 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/PKIXExtendedTM.java @@ -30,7 +30,6 @@ * @test * @bug 6916074 8170131 * @summary Add support for TLS 1.2 - * @enablePreview * @run main/othervm PKIXExtendedTM 0 * @run main/othervm PKIXExtendedTM 1 * @run main/othervm PKIXExtendedTM 2 diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java index a742b0b8a72c..fdb46c49e501 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/SunX509ExtendedTM.java @@ -30,7 +30,6 @@ * @test * @bug 6916074 * @summary Add support for TLS 1.2 - * @enablePreview * @run main/othervm SunX509ExtendedTM */ diff --git a/test/jdk/sun/security/validator/PKIXValAndRevCheckTests.java b/test/jdk/sun/security/validator/PKIXValAndRevCheckTests.java index 883d79057ebb..9a9601451990 100644 --- a/test/jdk/sun/security/validator/PKIXValAndRevCheckTests.java +++ b/test/jdk/sun/security/validator/PKIXValAndRevCheckTests.java @@ -27,7 +27,6 @@ * @summary Stapled OCSPResponses should be added to PKIXRevocationChecker * irrespective of revocationEnabled flag * @library /test/lib - * @enablePreview * @modules java.base/sun.security.validator * @build jdk.test.lib.Convert * @run main PKIXValAndRevCheckTests diff --git a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java b/test/jdk/sun/security/x509/X509CRLImpl/Verify.java index a10a18971d20..6f81ef5bd435 100644 --- a/test/jdk/sun/security/x509/X509CRLImpl/Verify.java +++ b/test/jdk/sun/security/x509/X509CRLImpl/Verify.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 7026347 * @summary X509CRL should have verify(PublicKey key, Provider sigProvider) - * @enablePreview */ import java.security.InvalidKeyException; From b1d719306f29d86bb7c5abd3ea6c457184daf7be Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 1 Sep 2026 15:40:43 +0000 Subject: [PATCH 176/223] 8391560: Shenandoah: JDK-8391299 broke some log tests Reviewed-by: ogillespie, kdnilsen, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 2 +- .../share/gc/shenandoah/shenandoahGenerationalControlThread.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index a76c81a4f06d..2cd1e1b1c39c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -97,7 +97,7 @@ void ShenandoahControlThread::run_service() { } } else if (is_gc_requested) { cause = requested_gc_cause; - heuristics->log_trigger("%s", GCCause::to_string(cause)); + heuristics->log_trigger("GC Request (%s)", GCCause::to_string(cause)); heuristics->record_requested_gc(); if (ShenandoahCollectorPolicy::should_run_full_gc(cause)) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 68ac2cdb1c7b..d03b527a2921 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -184,7 +184,7 @@ ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread: ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_explicit_gc(ShenandoahGCRequest &request) const { ShenandoahHeuristics* global_heuristics = _heap->global_generation()->heuristics(); request.generation = _heap->global_generation(); - global_heuristics->log_trigger("%s", GCCause::to_string(request.cause)); + global_heuristics->log_trigger("GC Request (%s)", GCCause::to_string(request.cause)); global_heuristics->record_requested_gc(); if (ShenandoahCollectorPolicy::should_run_full_gc(request.cause)) { From 445ab8594e3aef5e9d3bc69b22230f1bc2669378 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 1 Sep 2026 15:53:30 +0000 Subject: [PATCH 177/223] 8388932: Enable 'local variable is initialized but not referenced' warnings with MSVC in JDK Reviewed-by: prr, azvegint, erikj --- make/autoconf/flags-cflags.m4 | 5 +++-- make/common/TestFilesCompilation.gmk | 3 ++- make/modules/java.desktop/lib/AwtLibraries.gmk | 2 +- make/modules/java.desktop/lib/ClientLibraries.gmk | 2 +- src/java.base/windows/native/libjli/java_md.c | 6 ++---- .../windows/native/libawt/windows/awt_Component.h | 4 ++-- .../windows/native/libsplashscreen/splashscreen_sys.c | 3 +-- .../windows/native/jaccesswalker/jaccesswalker.cpp | 2 +- .../libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp | 4 ++-- 9 files changed, 15 insertions(+), 16 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 8f8a7af47fca..04a475c65b63 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -213,6 +213,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], WARNINGS_ENABLE_ADDITIONAL="" WARNINGS_ENABLE_ADDITIONAL_CXX="" WARNINGS_ENABLE_ADDITIONAL_JVM="" + WARNINGS_ENABLE_ADDITIONAL_JDK="-w34189" DISABLED_WARNINGS="4800 5105" CFLAGS_CONVERSION_WARNINGS= ;; @@ -623,8 +624,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], ADLC_LANGSTD_CXXFLAGS="$LANGSTD_CXXFLAGS" # CFLAGS WARNINGS STUFF - WARNING_CFLAGS_JDK_CONLY="$WARNINGS_ENABLE_ALL" - WARNING_CFLAGS_JDK_CXXONLY="$WARNINGS_ENABLE_ALL_CXX" + WARNING_CFLAGS_JDK_CONLY="$WARNINGS_ENABLE_ALL $WARNINGS_ENABLE_ADDITIONAL_JDK" + WARNING_CFLAGS_JDK_CXXONLY="$WARNINGS_ENABLE_ALL_CXX $WARNINGS_ENABLE_ADDITIONAL_JDK" WARNING_CFLAGS_JVM="$WARNINGS_ENABLE_ALL_JVM" # Set some additional per-OS defines. diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk index fd1c54eaf484..dd02d90c537e 100644 --- a/make/common/TestFilesCompilation.gmk +++ b/make/common/TestFilesCompilation.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -118,6 +118,7 @@ define SetupTestFilesCompilationBody DISABLED_WARNINGS_clang := format-nonliteral \ missing-field-initializers sometimes-uninitialized undef \ unused-but-set-variable unused-function unused-variable, \ + DISABLED_WARNINGS_microsoft := 4189, \ DEFAULT_LIBCXX := false, \ JDK_LIBS := $$($1_JDK_LIBS_$$(name)), \ LIBS := $$($1_LIBS) $$($1_LIBS_$$(name)), \ diff --git a/make/modules/java.desktop/lib/AwtLibraries.gmk b/make/modules/java.desktop/lib/AwtLibraries.gmk index 887dfab01dff..ca98434d3830 100644 --- a/make/modules/java.desktop/lib/AwtLibraries.gmk +++ b/make/modules/java.desktop/lib/AwtLibraries.gmk @@ -134,7 +134,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \ DISABLED_WARNINGS_clang_debug_trace.c := format-nonliteral, \ DISABLED_WARNINGS_clang_Trace.c := format-nonliteral, \ DISABLED_WARNINGS_clang_TransformHelper.c := sign-compare, \ - DISABLED_WARNINGS_microsoft := 4244 4996, \ + DISABLED_WARNINGS_microsoft := 4244 4996 4189, \ DISABLED_WARNINGS_microsoft_awt_Toolkit.cpp := 4267, \ LDFLAGS_windows := -delayload:comctl32.dll -delayload:comdlg32.dll \ -delayload:gdi32.dll -delayload:imm32.dll -delayload:ole32.dll \ diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 2326505d11c2..a09e54ce5ab4 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -343,7 +343,7 @@ else expansion-to-defined dangling-reference maybe-uninitialized HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers \ range-loop-analysis unused-variable - HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244 + HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244 4189 LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS) endif diff --git a/src/java.base/windows/native/libjli/java_md.c b/src/java.base/windows/native/libjli/java_md.c index 4382eceed7e9..4b3813f8c0f6 100644 --- a/src/java.base/windows/native/libjli/java_md.c +++ b/src/java.base/windows/native/libjli/java_md.c @@ -164,8 +164,6 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, } char *jvmtype; - int i = 0; - char** argv = *pargv; /* Find out where the JDK is that we will be using. */ if (!GetJDKInstallRoot(jdkroot, so_jdkroot)) { @@ -197,8 +195,8 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, /* Check if we need preload AWT */ #ifdef ENABLE_AWT_PRELOAD - argv = *pargv; - for (i = 0; i < *pargc ; i++) { + char** argv = *pargv; + for (int i = 0; i < *pargc ; i++) { /* Tests the "turn on" parameter only if not set yet. */ if (awtPreloadD3D < 0) { if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 42a88c24f8c8..e0586c207b6c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -309,7 +309,7 @@ class AwtComponent : public AwtObject { DASSERT(GetHWnd()); // SetWindowLong() error handling as recommended by Win32 API doc. ::SetLastError(0); - DWORD ret = ::SetWindowLong(GetHWnd(), GWL_STYLE, style); + [[maybe_unused]] DWORD ret = ::SetWindowLong(GetHWnd(), GWL_STYLE, style); DASSERT(ret != 0 || ::GetLastError() == 0); } INLINE virtual LONG GetStyleEx() { @@ -320,7 +320,7 @@ class AwtComponent : public AwtObject { DASSERT(GetHWnd()); // SetWindowLong() error handling as recommended by Win32 API doc. ::SetLastError(0); - DWORD ret = ::SetWindowLong(GetHWnd(), GWL_EXSTYLE, style); + [[maybe_unused]] DWORD ret = ::SetWindowLong(GetHWnd(), GWL_EXSTYLE, style); DASSERT(ret != 0 || ::GetLastError() == 0); } diff --git a/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c b/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c index 2f700c00dafb..4e26ade6c43d 100644 --- a/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c +++ b/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -577,7 +577,6 @@ SplashGetScaledImageName(const char* jarName, const char* fileName, { float dpiScaleX = -1.0f; float dpiScaleY = -1.0f; - FILE *fp = NULL; *scaleFactor = 1.0; GetScreenDpi(getPrimaryMonitor(), &dpiScaleX, &dpiScaleY); *scaleFactor = dpiScaleX > 0 ? dpiScaleX / 96 : *scaleFactor; diff --git a/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp b/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp index 797e6fc4762f..c802c1146b80 100644 --- a/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp +++ b/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp @@ -557,7 +557,7 @@ void Jaccesswalker::addComponentNodes(long vmID, AccessibleContext context, tvis.hInsertAfter = TVI_LAST; // make tree in order given tvis.item = tvi; - HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); + [[maybe_unused]] HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); } } diff --git a/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp b/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp index b34231af83c3..e301185c008e 100644 --- a/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp +++ b/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -268,7 +268,7 @@ AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) { DEBUG_CODE(PackageType *type = (PackageType *) memoryMappedView); DEBUG_CODE(if (*type == cGetAccessibleTextItemsPackage) {) DEBUG_CODE(AppendToCallInfo(" 'memoryMappedView' now contains:")); - DEBUG_CODE(GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType))); + DEBUG_CODE([[maybe_unused]] GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType))); DEBUG_CODE(snprintf(outputBuf, sizeof(outputBuf), " PackageType = %X", *type)); DEBUG_CODE(AppendToCallInfo(outputBuf)); DEBUG_CODE(}) From dbd77accbc1a1aaee859d3b308e1eff651aa9dce Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 1 Sep 2026 16:00:01 +0000 Subject: [PATCH 178/223] 8389058: javac crashes with StackOverflowError in Resolve.findInheritedMemberType when a class illegally extends itself and references a member type Co-authored-by: Jan Lahoda Reviewed-by: mcimadamore --- .../classes/com/sun/tools/javac/comp/TypeEnter.java | 2 +- test/langtools/tools/javac/6863465/T6863465a.out | 3 ++- test/langtools/tools/javac/6863465/T6863465b.out | 4 +++- test/langtools/tools/javac/6863465/T6863465c.out | 3 ++- test/langtools/tools/javac/6863465/T6863465d.out | 4 +++- test/langtools/tools/javac/ClassCycle/ClassCycle5.java | 9 +++++++++ test/langtools/tools/javac/ClassCycle/ClassCycle5.out | 3 +++ 7 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 test/langtools/tools/javac/ClassCycle/ClassCycle5.java create mode 100644 test/langtools/tools/javac/ClassCycle/ClassCycle5.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index e6c28d3bf197..5aed62995e64 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -770,7 +770,6 @@ protected void attribSuperTypes(Env env, Env baseEnv) true, false, false) : syms.objectType; } - ct.supertype_field = modelMissingTypes(baseEnv, supertype, extending, false); // Determine interfaces. ListBuffer interfaces = new ListBuffer<>(); @@ -789,6 +788,7 @@ protected void attribSuperTypes(Env env, Env baseEnv) } } + ct.supertype_field = modelMissingTypes(baseEnv, supertype, extending, false); if ((sym.flags_field & ANNOTATION) != 0) { ct.interfaces_field = List.of(syms.annotationType); ct.all_interfaces_field = ct.interfaces_field; diff --git a/test/langtools/tools/javac/6863465/T6863465a.out b/test/langtools/tools/javac/6863465/T6863465a.out index 1c4513f21aae..fd354cec052a 100644 --- a/test/langtools/tools/javac/6863465/T6863465a.out +++ b/test/langtools/tools/javac/6863465/T6863465a.out @@ -1,2 +1,3 @@ +T6863465a.java:13:42: compiler.err.cant.resolve.location: kindname.class, b, , , (compiler.misc.location: kindname.class, T6863465a.c, null) T6863465a.java:11:12: compiler.err.cyclic.inheritance: T6863465a.c -1 error +2 errors diff --git a/test/langtools/tools/javac/6863465/T6863465b.out b/test/langtools/tools/javac/6863465/T6863465b.out index cb16e9336128..907b200acb43 100644 --- a/test/langtools/tools/javac/6863465/T6863465b.out +++ b/test/langtools/tools/javac/6863465/T6863465b.out @@ -1,2 +1,4 @@ +T6863465b.java:13:42: compiler.err.cant.resolve.location: kindname.class, b, , , (compiler.misc.location: kindname.class, T6863465b.c, null) +T6863465b.java:11:47: compiler.err.cant.resolve.location: kindname.class, d, , , (compiler.misc.location: kindname.class, T6863465b.z, null) T6863465b.java:11:12: compiler.err.cyclic.inheritance: T6863465b.c -1 error +3 errors diff --git a/test/langtools/tools/javac/6863465/T6863465c.out b/test/langtools/tools/javac/6863465/T6863465c.out index 1dab88a1190d..b6efbbee1c75 100644 --- a/test/langtools/tools/javac/6863465/T6863465c.out +++ b/test/langtools/tools/javac/6863465/T6863465c.out @@ -1,3 +1,4 @@ +T6863465c.java:13:42: compiler.err.cant.resolve.location: kindname.class, y, , , (compiler.misc.location: kindname.class, T6863465c.z, null) T6863465c.java:13:47: compiler.err.cant.resolve.location: kindname.class, d, , , (compiler.misc.location: kindname.class, T6863465c.z, null) T6863465c.java:11:12: compiler.err.cyclic.inheritance: T6863465c.z -2 errors +3 errors diff --git a/test/langtools/tools/javac/6863465/T6863465d.out b/test/langtools/tools/javac/6863465/T6863465d.out index b30d9effa172..3d508557443c 100644 --- a/test/langtools/tools/javac/6863465/T6863465d.out +++ b/test/langtools/tools/javac/6863465/T6863465d.out @@ -1,3 +1,5 @@ +T6863465d.java:13:42: compiler.err.cant.resolve.location: kindname.class, b, , , (compiler.misc.location: kindname.class, T6863465d.c, null) T6863465d.java:13:47: compiler.err.cant.resolve.location: kindname.class, w, , , (compiler.misc.location: kindname.class, T6863465d.c, null) +T6863465d.java:11:47: compiler.err.cant.resolve.location: kindname.class, d, , , (compiler.misc.location: kindname.class, T6863465d.z, null) T6863465d.java:11:12: compiler.err.cyclic.inheritance: T6863465d.c -2 errors +4 errors diff --git a/test/langtools/tools/javac/ClassCycle/ClassCycle5.java b/test/langtools/tools/javac/ClassCycle/ClassCycle5.java new file mode 100644 index 000000000000..84ac7251d628 --- /dev/null +++ b/test/langtools/tools/javac/ClassCycle/ClassCycle5.java @@ -0,0 +1,9 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8389058 + * @summary Verify that resolving a qualified type through a self-referential + * (cyclic) supertype doesn't crash the compiler with StackOverflowError + * @compile/fail/ref=ClassCycle5.out -XDrawDiagnostics ClassCycle5.java + */ + +class ClassCycle5 extends ClassCycle5 implements ClassCycle5.NoSuchType {} diff --git a/test/langtools/tools/javac/ClassCycle/ClassCycle5.out b/test/langtools/tools/javac/ClassCycle/ClassCycle5.out new file mode 100644 index 000000000000..fb25b22e8cf9 --- /dev/null +++ b/test/langtools/tools/javac/ClassCycle/ClassCycle5.out @@ -0,0 +1,3 @@ +ClassCycle5.java:9:61: compiler.err.cant.resolve.location: kindname.class, NoSuchType, , , (compiler.misc.location: kindname.class, ClassCycle5, null) +ClassCycle5.java:9:1: compiler.err.cyclic.inheritance: ClassCycle5 +2 errors From 2e08ef3186998d70a76d464ea297266ca512a63d Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 1 Sep 2026 16:30:32 +0000 Subject: [PATCH 179/223] 8389730: [Valhalla] Fix two masked inverted conditions in LibraryCallKit::should_bail_out_on_non_ref_arrays() Reviewed-by: thartmann, mchevalier --- src/hotspot/share/opto/library_call.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6f4e9d9463df..c16888ddf97e 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5369,7 +5369,7 @@ bool LibraryCallKit::should_bail_out_on_non_ref_arrays(const TypeAryPtr* src_typ return true; } - if (UseArrayFlattening) { + if (!UseArrayFlattening) { // The remaining checks revolve around array flatness. Without array flatness, we don't need the stronger non-ref // runtime check excluding flat arrays. return false; @@ -5391,7 +5391,7 @@ bool LibraryCallKit::should_bail_out_on_non_ref_arrays(const TypeAryPtr* src_typ // TODO 8251971: Optimize for the case when flat src/dst are later found to not contain // oops (i.e., move this check to the macro expansion phase). BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - if (bs->array_copy_requires_gc_barriers(true, T_OBJECT, false, false, BarrierSetC2::Parsing)) { + if (!bs->array_copy_requires_gc_barriers(true, T_OBJECT, false, false, BarrierSetC2::Parsing)) { // No barriers required. return false; } From 523ab61057d9396569499a20e33c1e3683203b67 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Tue, 1 Sep 2026 18:54:13 +0000 Subject: [PATCH 180/223] 8390175: FFM upcallstub can skip reinit_heapbase() right before restore_callee_saved_registers Reviewed-by: jvernee, vlivanov --- src/hotspot/cpu/x86/upcallLinker_x86_64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index 095767663e55..eb5cda566060 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -351,7 +351,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, __ lea(c_rarg0, Address(rsp, frame_data_offset)); // stack already aligned __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_exit))); - __ reinit_heapbase(); + assert(!UseCompressedOops || !abi.is_volatile_reg(r12_heapbase), "r12_heapbase is not a volatile_reg!"); __ block_comment("} on_exit"); restore_callee_saved_registers(_masm, abi, reg_save_area_offset); From 6120f1b2e1e240b812d7bb58006d39be1fa071a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 1 Sep 2026 19:17:04 +0000 Subject: [PATCH 181/223] 8391478: Remove java.lang.runtime.Carriers Reviewed-by: vklang, liach --- .../classes/java/lang/runtime/Carriers.java | 1005 ----------------- test/jdk/java/lang/runtime/CarriersTest.java | 166 --- 2 files changed, 1171 deletions(-) delete mode 100644 src/java.base/share/classes/java/lang/runtime/Carriers.java delete mode 100644 test/jdk/java/lang/runtime/CarriersTest.java diff --git a/src/java.base/share/classes/java/lang/runtime/Carriers.java b/src/java.base/share/classes/java/lang/runtime/Carriers.java deleted file mode 100644 index a74144fcbebd..000000000000 --- a/src/java.base/share/classes/java/lang/runtime/Carriers.java +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.runtime; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -import jdk.internal.misc.Unsafe; -import jdk.internal.util.ReferencedKeyMap; - -import static java.lang.invoke.MethodType.methodType; - -/** - * A carrier is an opaque object that can be used to store component values - * while avoiding primitive boxing associated with collection objects. Component values - * can be primitive or Object. - *

      - * Clients can create new carrier instances by describing a carrier shape, that - * is, a {@linkplain MethodType method type} whose parameter types describe the types of - * the carrier component values, or by providing the parameter types directly. - * - * {@snippet : - * // Create a carrier for a string and an integer - * CarrierElements elements = CarrierFactory.of(String.class, int.class); - * // Fetch the carrier constructor MethodHandle - * MethodHandle initializingConstructor = elements.initializingConstructor(); - * // Fetch the list of carrier component MethodHandles - * List components = elements.components(); - * - * // Create an instance of the carrier with a string and an integer - * Object carrier = initializingConstructor.invokeExact("abc", 10); - * // Extract the first component, type string - * String string = (String)components.get(0).invokeExact(carrier); - * // Extract the second component, type int - * int i = (int)components.get(1).invokeExact(carrier); - * } - * - * Alternatively, the client can use static methods when the carrier use is scattered. - * This is possible since {@link Carriers} ensures that the same underlying carrier - * class is used when the same component types are provided. - * - * {@snippet : - * // Describe carrier using a MethodType - * MethodType mt = MethodType.methodType(Object.class, String.class, int.class); - * // Fetch the carrier constructor MethodHandle - * MethodHandle constructor = Carriers.constructor(mt); - * // Fetch the list of carrier component MethodHandles - * List components = Carriers.components(mt); - * } - * - * @implNote The strategy for storing components is deliberately left unspecified - * so that future improvements will not be hampered by issues of backward compatibility. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -final class Carriers { - /** - * Maximum number of components in a carrier (based on the maximum - * number of args to a constructor.) - */ - public static final int MAX_COMPONENTS = 255 - /* this */ 1; - - /** - * Number of integer slots used by a long. - */ - static final int LONG_SLOTS = Long.SIZE / Integer.SIZE; - - /* - * Initialize {@link MethodHandle} constants. - */ - static { - try { - Lookup lookup = MethodHandles.lookup(); - FLOAT_TO_INT = lookup.findStatic(Float.class, "floatToRawIntBits", - methodType(int.class, float.class)); - INT_TO_FLOAT = lookup.findStatic(Float.class, "intBitsToFloat", - methodType(float.class, int.class)); - DOUBLE_TO_LONG = lookup.findStatic(Double.class, "doubleToRawLongBits", - methodType(long.class, double.class)); - LONG_TO_DOUBLE = lookup.findStatic(Double.class, "longBitsToDouble", - methodType(double.class, long.class)); - } catch (ReflectiveOperationException ex) { - throw new AssertionError("carrier static init fail", ex); - } - } - - /* - * float/double conversions. - */ - private static final MethodHandle FLOAT_TO_INT; - private static final MethodHandle INT_TO_FLOAT; - private static final MethodHandle DOUBLE_TO_LONG; - private static final MethodHandle LONG_TO_DOUBLE; - - /** - * Given an initializer {@link MethodHandle} recast and reorder arguments to - * match shape. - * - * @param carrierShape carrier shape - * @param initializer carrier constructor to reshape - * - * @return constructor with arguments recasted and reordered - */ - static MethodHandle reshapeInitializer(CarrierShape carrierShape, - MethodHandle initializer) { - int count = carrierShape.count(); - Class[] ptypes = carrierShape.ptypes(); - int objectIndex = carrierShape.objectOffset() + 1; - int intIndex = carrierShape.intOffset() + 1; - int longIndex = carrierShape.longOffset() + 1; - int[] reorder = new int[count + 1]; - Class[] permutePTypes = new Class[count + 1]; - MethodHandle[] filters = new MethodHandle[count + 1]; - boolean hasFilters = false; - permutePTypes[0] = CarrierObject.class; - reorder[0] = 0; - int index = 1; - - for (Class ptype : ptypes) { - MethodHandle filter = null; - int from; - - if (!ptype.isPrimitive()) { - from = objectIndex++; - ptype = Object.class; - } else if (ptype == double.class) { - from = longIndex++; - filter = DOUBLE_TO_LONG; - } else if (ptype == float.class) { - from = intIndex++; - filter = FLOAT_TO_INT; - } else if (ptype == long.class) { - from = longIndex++; - } else { - from = intIndex++; - ptype = int.class; - } - - permutePTypes[index] = ptype; - reorder[from] = index++; - - if (filter != null) { - filters[from] = filter; - hasFilters = true; - } - } - - if (hasFilters) { - initializer = MethodHandles.filterArguments(initializer, 0, filters); - } - - MethodType permutedMethodType = - methodType(initializer.type().returnType(), permutePTypes); - initializer = MethodHandles.permuteArguments(initializer, - permutedMethodType, reorder); - initializer = MethodHandles.explicitCastArguments(initializer, - methodType(CarrierObject.class, ptypes).insertParameterTypes(0, CarrierObject.class)); - - return initializer; - } - - /** - * Given components array, recast and reorder components to match shape. - * - * @param carrierShape carrier reshape - * @param components carrier components to reshape - * - * @return list of components reshaped - */ - static List reshapeComponents(CarrierShape carrierShape, - MethodHandle[] components) { - int count = carrierShape.count(); - Class[] ptypes = carrierShape.ptypes(); - MethodHandle[] reorder = new MethodHandle[count]; - int objectIndex = carrierShape.objectOffset(); - int intIndex = carrierShape.intOffset(); - int longIndex = carrierShape.longOffset(); - int index = 0; - - for (Class ptype : ptypes) { - MethodHandle component; - - if (!ptype.isPrimitive()) { - component = components[objectIndex++]; - } else if (ptype == double.class) { - component = MethodHandles.filterReturnValue( - components[longIndex++], LONG_TO_DOUBLE); - } else if (ptype == float.class) { - component = MethodHandles.filterReturnValue( - components[intIndex++], INT_TO_FLOAT); - } else if (ptype == long.class) { - component = components[longIndex++]; - } else { - component = components[intIndex++]; - } - - MethodType methodType = methodType(ptype, CarrierObject.class); - reorder[index++] = - MethodHandles.explicitCastArguments(component, methodType); - } - - return List.of(reorder); - } - - /** - * Factory for carriers that are backed by long[] and Object[]. - */ - static final class CarrierObjectFactory { - /** - * Unsafe access. - */ - private static final Unsafe UNSAFE; - - /* - * Constructor accessor MethodHandles. - */ - private static final MethodHandle CONSTRUCTOR; - private static final MethodHandle GET_LONG; - private static final MethodHandle PUT_LONG; - private static final MethodHandle GET_INTEGER; - private static final MethodHandle PUT_INTEGER; - private static final MethodHandle GET_OBJECT; - private static final MethodHandle PUT_OBJECT; - - static { - try { - UNSAFE = Unsafe.getUnsafe(); - Lookup lookup = MethodHandles.lookup(); - CONSTRUCTOR = lookup.findConstructor(CarrierObject.class, - methodType(void.class, int.class, int.class)); - GET_LONG = lookup.findVirtual(CarrierObject.class, "getLong", - methodType(long.class, int.class)); - PUT_LONG = lookup.findVirtual(CarrierObject.class, "putLong", - methodType(CarrierObject.class, int.class, long.class)); - GET_INTEGER = lookup.findVirtual(CarrierObject.class, "getInteger", - methodType(int.class, int.class)); - PUT_INTEGER = lookup.findVirtual(CarrierObject.class, "putInteger", - methodType(CarrierObject.class, int.class, int.class)); - GET_OBJECT = lookup.findVirtual(CarrierObject.class, "getObject", - methodType(Object.class, int.class)); - PUT_OBJECT = lookup.findVirtual(CarrierObject.class, "putObject", - methodType(CarrierObject.class, int.class, Object.class)); - } catch (ReflectiveOperationException ex) { - throw new AssertionError("carrier static init fail", ex); - } - } - - /** - * Constructor builder. - * - * @param carrierShape carrier object shape - * - * @return {@link MethodHandle} to generic carrier constructor. - */ - MethodHandle constructor(CarrierShape carrierShape) { - int objectCount = carrierShape.objectCount(); - int primitiveCount = carrierShape.primitiveCount(); - - MethodHandle constructor = MethodHandles.insertArguments(CONSTRUCTOR, - 0, primitiveCount, objectCount); - - return constructor; - } - - /** - * Adds constructor arguments for each of the allocated slots. - * - * @param carrierShape carrier object shape - * - * @return {@link MethodHandle} to specific carrier constructor. - */ - MethodHandle initializer(CarrierShape carrierShape) { - int longCount = carrierShape.longCount(); - int intCount = carrierShape.intCount(); - int objectCount = carrierShape.objectCount(); - MethodHandle initializer = MethodHandles.identity(CarrierObject.class); - - // long array index - int index = 0; - for (int i = 0; i < longCount; i++) { - MethodHandle put = MethodHandles.insertArguments(PUT_LONG, 1, index++); - initializer = MethodHandles.collectArguments(put, 0, initializer); - } - - // transition to int array index (double number of longs) - index *= LONG_SLOTS; - for (int i = 0; i < intCount; i++) { - MethodHandle put = MethodHandles.insertArguments(PUT_INTEGER, 1, index++); - initializer = MethodHandles.collectArguments(put, 0, initializer); - } - - for (int i = 0; i < objectCount; i++) { - MethodHandle put = MethodHandles.insertArguments(PUT_OBJECT, 1, i); - initializer = MethodHandles.collectArguments(put, 0, initializer); - } - - return initializer; - } - - /** - * Utility to construct the basic accessors from the components. - * - * @param carrierShape carrier object shape - * - * @return array of carrier accessors - */ - MethodHandle[] createComponents(CarrierShape carrierShape) { - int longCount = carrierShape.longCount(); - int intCount = carrierShape.intCount(); - int objectCount = carrierShape.objectCount(); - MethodHandle[] components = - new MethodHandle[carrierShape.ptypes().length]; - - // long array index - int index = 0; - // component index - int comIndex = 0; - for (int i = 0; i < longCount; i++) { - components[comIndex++] = MethodHandles.insertArguments(GET_LONG, 1, index++); - } - - // transition to int array index (double number of longs) - index *= LONG_SLOTS; - for (int i = 0; i < intCount; i++) { - components[comIndex++] = MethodHandles.insertArguments(GET_INTEGER, 1, index++); - } - - for (int i = 0; i < objectCount; i++) { - components[comIndex++] = MethodHandles.insertArguments(GET_OBJECT, 1, i); - } - return components; - } - - /** - * Cache mapping {@link MethodType} to previously defined {@link CarrierElements}. - */ - private static final Map - methodTypeCache = ReferencedKeyMap.create(false, ConcurrentHashMap::new); - - /** - * Permute a raw constructor and component accessor {@link MethodHandle MethodHandles} to - * match the order and types of the parameter types. - * - * @param carrierShape carrier object shape - * - * @return {@link CarrierElements} instance - */ - CarrierElements carrier(CarrierShape carrierShape) { - return methodTypeCache.computeIfAbsent(carrierShape.methodType, (mt) -> { - MethodHandle constructor = constructor(carrierShape); - MethodHandle initializer = initializer(carrierShape); - MethodHandle[] components = createComponents(carrierShape); - return new CarrierElements( - carrierShape, - CarrierObject.class, - constructor, - reshapeInitializer(carrierShape, initializer), - reshapeComponents(carrierShape, components)); - }); - } - } - - /** - * Wrapper object for carrier data. Instance types are stored in the {@code objects} - * array, while primitive types are recast to {@code int/long} and stored in the - * {@code primitives} array. Primitive byte, short, char, boolean and int are stored as - * integers. Longs and doubles are stored as longs. Longs take up the first part of the - * primitives array using normal indices. Integers follow using int[] indices offset beyond - * the longs using unsafe getInt/putInt. - */ - static class CarrierObject { - /** - * Carrier for primitive values. - */ - private final long[] primitives; - - /** - * Carrier for objects; - */ - private final Object[] objects; - - /** - * Constructor. - * - * @param primitiveCount slot count required for primitives - * @param objectCount slot count required for objects - */ - protected CarrierObject(int primitiveCount, int objectCount) { - this.primitives = createPrimitivesArray(primitiveCount); - this.objects = createObjectsArray(objectCount); - } - - /** - * Create a primitives array of an appropriate length. - * - * @param primitiveCount slot count required for primitives - * - * @return primitives array of an appropriate length. - */ - private long[] createPrimitivesArray(int primitiveCount) { - return primitiveCount != 0 ? new long[(primitiveCount + 1) / LONG_SLOTS] : null; - } - - /** - * Create a objects array of an appropriate length. - * - * @param objectCount slot count required for objects - * - * @return objects array of an appropriate length. - */ - private Object[] createObjectsArray(int objectCount) { - return objectCount != 0 ? new Object[objectCount] : null; - } - - /** - * Compute offset for unsafe access to long. - * - * @param i index in primitive[] - * - * @return offset for unsafe access - */ - private static long offsetToLong(int i) { - return Unsafe.ARRAY_LONG_BASE_OFFSET + - (long)i * Unsafe.ARRAY_LONG_INDEX_SCALE; - } - - /** - * Compute offset for unsafe access to int. - * - * @param i index in primitive[] - * - * @return offset for unsafe access - */ - private static long offsetToInt(int i) { - return Unsafe.ARRAY_LONG_BASE_OFFSET + - (long)i * Unsafe.ARRAY_INT_INDEX_SCALE; - } - - /** - * Compute offset for unsafe access to object. - * - * @param i index in objects[] - * - * @return offset for unsafe access - */ - private static long offsetToObject(int i) { - return Unsafe.ARRAY_OBJECT_BASE_OFFSET + - (long)i * Unsafe.ARRAY_OBJECT_INDEX_SCALE; - } - - /** - * {@return long value at index} - * - * @param i array index - */ - private long getLong(int i) { - return CarrierObjectFactory.UNSAFE.getLong(primitives, offsetToLong(i)); - } - - /** - * Put a long value into the primitive[]. - * - * @param i array index - * @param value long value to store - * - * @return this object - */ - private CarrierObject putLong(int i, long value) { - CarrierObjectFactory.UNSAFE.putLong(primitives, offsetToLong(i), value); - - return this; - } - - /** - * {@return int value at index} - * - * @param i array index - */ - private int getInteger(int i) { - return CarrierObjectFactory.UNSAFE.getInt(primitives, offsetToInt(i)); - } - - /** - * Put a int value into the int[]. - * - * @param i array index - * @param value int value to store - * - * @return this object - */ - private CarrierObject putInteger(int i, int value) { - CarrierObjectFactory.UNSAFE.putInt(primitives, offsetToInt(i), value); - - return this; - } - - /** - * {@return Object value at index} - * - * @param i array index - */ - private Object getObject(int i) { - return CarrierObjectFactory.UNSAFE.getReference(objects, offsetToObject(i)); - } - - /** - * Put a object value into the objects[]. - * - * @param i array index - * @param value object value to store - * - * @return this object - */ - private CarrierObject putObject(int i, Object value) { - CarrierObjectFactory.UNSAFE.putReference(objects, offsetToObject(i), value); - - return this; - } - } - - /** - * Class used to tally and track the number of ints, longs and objects. - * - * @param longCount number of longs and doubles - * @param intCount number of byte, short, int, chars and booleans - * @param objectCount number of objects - */ - private record CarrierCounts(int longCount, int intCount, int objectCount) { - /** - * Count the number of fields required in each of Object, int and long. - * - * @param ptypes parameter types - * - * @return a {@link CarrierCounts} instance containing counts - */ - static CarrierCounts tally(Class[] ptypes) { - return tally(ptypes, ptypes.length); - } - - /** - * Count the number of fields required in each of Object, int and long - * limited to the first {@code n} parameters. - * - * @param ptypes parameter types - * @param n number of parameters to check - * - * @return a {@link CarrierCounts} instance containing counts - */ - private static CarrierCounts tally(Class[] ptypes, int n) { - int longCount = 0; - int intCount = 0; - int objectCount = 0; - - for (int i = 0; i < n; i++) { - Class ptype = ptypes[i]; - - if (!ptype.isPrimitive()) { - objectCount++; - } else if (ptype == long.class || ptype == double.class) { - longCount++; - } else { - intCount++; - } - } - - return new CarrierCounts(longCount, intCount, objectCount); - } - - /** - * {@return total number of components} - */ - private int count() { - return longCount + intCount + objectCount; - } - - /** - * {@return total number of slots} - */ - private int slotCount() { - return longCount * LONG_SLOTS + intCount + objectCount; - } - - } - - /** - * Constructor - */ - private Carriers() { - throw new AssertionError("private constructor"); - } - - /** - * Shape of carrier based on counts of each of the three fundamental data - * types. - */ - private static class CarrierShape { - /** - * {@link MethodType} providing types for the carrier's components. - */ - final MethodType methodType; - - /** - * Counts of different parameter types. - */ - final CarrierCounts counts; - - /** - * Constructor. - * - * @param methodType {@link MethodType} providing types for the - * carrier's components - */ - public CarrierShape(MethodType methodType) { - this.methodType = methodType; - this.counts = CarrierCounts.tally(methodType.parameterArray()); - } - - /** - * {@return number of long fields needed} - */ - int longCount() { - return counts.longCount(); - } - - /** - * {@return number of int fields needed} - */ - int intCount() { - return counts.intCount(); - } - - /** - * {@return number of object fields needed} - */ - int objectCount() { - return counts.objectCount(); - } - - /** - * {@return slot count required for primitives} - */ - int primitiveCount() { - return counts.longCount() * LONG_SLOTS + counts.intCount(); - } - - /** - * {@return array of parameter types} - */ - Class[] ptypes() { - return methodType.parameterArray(); - } - - /** - * {@return number of components} - */ - int count() { - return counts.count(); - } - - /** - * {@return number of slots used} - */ - int slotCount() { - return counts.slotCount(); - } - - /** - * {@return index of first long component} - */ - int longOffset() { - return 0; - } - - /** - * {@return index of first int component} - */ - int intOffset() { - return longCount(); - } - - /** - * {@return index of first object component} - */ - int objectOffset() { - return longCount() + intCount(); - } - } - - /** - * This factory class generates {@link CarrierElements} instances containing the - * {@link MethodHandle MethodHandles} to the constructor and accessors of a carrier - * object. - *

      - * Clients can create instances by describing a carrier shape, that - * is, a {@linkplain MethodType method type} whose parameter types describe the types of - * the carrier component values, or by providing the parameter types directly. - */ - static final class CarrierFactory { - /** - * Constructor - */ - private CarrierFactory() { - throw new AssertionError("private constructor"); - } - - private static final CarrierObjectFactory FACTORY = new CarrierObjectFactory(); - - /** - * Factory method to return a {@link CarrierElements} instance that matches the shape of - * the supplied {@link MethodType}. The return type of the {@link MethodType} is ignored. - * - * @param methodType {@link MethodType} whose parameter types supply the - * the shape of the carrier's components - * - * @return {@link CarrierElements} instance - * - * @throws NullPointerException is methodType is null - * @throws IllegalArgumentException if number of component slots exceeds maximum - */ - static CarrierElements of(MethodType methodType) { - Objects.requireNonNull(methodType, "methodType must not be null"); - MethodType constructorMT = methodType.changeReturnType(Object.class); - CarrierShape carrierShape = new CarrierShape(constructorMT); - int slotCount = carrierShape.slotCount(); - - if (MAX_COMPONENTS < slotCount) { - throw new IllegalArgumentException("Exceeds maximum number of component slots"); - } - - return FACTORY.carrier(carrierShape); - } - - /** - * Factory method to return a {@link CarrierElements} instance that matches the shape of - * the supplied parameter types. - * - * @param ptypes parameter types that supply the shape of the carrier's components - * - * @return {@link CarrierElements} instance - * - * @throws NullPointerException is ptypes is null - * @throws IllegalArgumentException if number of component slots exceeds maximum - */ - static CarrierElements of(Class...ptypes) { - Objects.requireNonNull(ptypes, "ptypes must not be null"); - return of(methodType(Object.class, ptypes)); - } - } - - /** - * Instances of this class provide the {@link MethodHandle MethodHandles} to the - * constructor and accessors of a carrier object. The original component types can be - * gleaned from the parameter types of the constructor {@link MethodHandle} or by the - * return types of the components' {@link MethodHandle MethodHandles}. - */ - static final class CarrierElements { - /** - * Slot count required for objects. - */ - private final int objectCount; - - /** - * Slot count required for primitives. - */ - private final int primitiveCount; - - /** - * Underlying carrier class. - */ - private final Class carrierClass; - - /** - * Constructor {@link MethodHandle}. - */ - private final MethodHandle constructor; - - /** - * Initializer {@link MethodHandle}. - */ - private final MethodHandle initializer; - - /** - * List of component {@link MethodHandle MethodHandles} - */ - private final List components; - - /** - * Constructor - */ - private CarrierElements() { - throw new AssertionError("private constructor"); - } - - /** - * Constructor - */ - CarrierElements(CarrierShape carrierShape, - Class carrierClass, - MethodHandle constructor, - MethodHandle initializer, - List components) { - this.objectCount = carrierShape.objectCount(); - this.primitiveCount = carrierShape.primitiveCount(); - this.carrierClass = carrierClass; - this.constructor = constructor; - this.initializer = initializer; - this.components = components; - } - - /** - * {@return slot count required for objects} - */ - int objectCount() { - return objectCount; - } - - /** - * {@return slot count required for primitives} - */ - int primitiveCount() { - return primitiveCount; - } - - /** - * {@return the underlying carrier class} - */ - Class carrierClass() { - return carrierClass; - } - - /** - * {@return the constructor {@link MethodHandle} for the carrier. The - * carrier constructor will always have a return type of {@link Object} } - */ - MethodHandle constructor() { - return constructor; - } - - /** - * {@return the initializer {@link MethodHandle} for the carrier} - */ - MethodHandle initializer() { - return initializer; - } - - /** - * Return the constructor plus initializer {@link MethodHandle} for the carrier. - * The {@link MethodHandle} will always have a return type of {@link Object}. - * @return the constructor plus initializer {@link MethodHandle} - */ - MethodHandle initializingConstructor() { - return MethodHandles.foldArguments(initializer, 0, constructor); - } - - /** - * {@return immutable list of component accessor {@link MethodHandle MethodHandles} - * for all the carrier's components. The receiver type of the accessors - * will always be {@link Object} } - */ - List components() { - return components; - } - - /** - * {@return a component accessor {@link MethodHandle} for component {@code i}. - * The receiver type of the accessor will be {@link Object} } - * - * @param i component index - * - * @throws IllegalArgumentException if {@code i} is out of bounds - */ - MethodHandle component(int i) { - if (i < 0 || components.size() <= i) { - throw new IllegalArgumentException("i is out of bounds " + i + - " of " + components.size()); - } - - return components.get(i); - } - - @Override - public String toString() { - return "Carrier" + constructor.type().parameterList(); - } - } - - /** - * {@return the underlying carrier class of the carrier representing {@code methodType} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - */ - static Class carrierClass(MethodType methodType) { - return CarrierFactory.of(methodType).carrierClass(); - } - - /** - * {@return the constructor {@link MethodHandle} for the carrier representing {@code - * methodType}. The carrier constructor will always have a return type of {@link Object} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - */ - static MethodHandle constructor(MethodType methodType) { - MethodHandle constructor = CarrierFactory.of(methodType).constructor(); - constructor = constructor.asType(constructor.type().changeReturnType(Object.class)); - return constructor; - } - - /** - * {@return the initializer {@link MethodHandle} for the carrier representing {@code - * methodType}. The carrier initializer will always take an {@link Object} along with - * component values and a return type of {@link Object} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - */ - static MethodHandle initializer(MethodType methodType) { - MethodHandle initializer = CarrierFactory.of(methodType).initializer(); - initializer = initializer.asType(initializer.type() - .changeReturnType(Object.class).changeParameterType(0, Object.class)); - return initializer; - } - - /** - * {@return the combination {@link MethodHandle} of the constructor and initializer - * for the carrier representing {@code methodType}. The carrier constructor/initializer - * will always take the component values and a return type of {@link Object} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - */ - static MethodHandle initializingConstructor(MethodType methodType) { - MethodHandle constructor = CarrierFactory.of(methodType).initializingConstructor(); - constructor = constructor.asType(constructor.type().changeReturnType(Object.class)); - return constructor; - } - - /** - * {@return immutable list of component accessor {@link MethodHandle MethodHandles} for - * all the components of the carrier representing {@code methodType}. The receiver type of - * the accessors will always be {@link Object} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - */ - static List components(MethodType methodType) { - return CarrierFactory - .of(methodType) - .components() - .stream() - .map(c -> c.asType(c.type().changeParameterType(0, Object.class))) - .toList(); - } - - /** - * {@return a component accessor {@link MethodHandle} for component {@code i} of the - * carrier representing {@code methodType}. The receiver type of the accessor will always - * be {@link Object} } - * - * @param methodType {@link MethodType} whose parameter types supply the shape of the - * carrier's components - * @param i component index - * - * @throws IllegalArgumentException if {@code i} is out of bounds - */ - static MethodHandle component(MethodType methodType, int i) { - MethodHandle component = CarrierFactory.of(methodType).component(i); - component = component.asType(component.type().changeParameterType(0, Object.class)); - return component; - } - -} diff --git a/test/jdk/java/lang/runtime/CarriersTest.java b/test/jdk/java/lang/runtime/CarriersTest.java deleted file mode 100644 index 9b805f2c832c..000000000000 --- a/test/jdk/java/lang/runtime/CarriersTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Test features provided by the Carriers class. - * @modules java.base/java.lang.runtime - * @enablePreview true - * @compile --patch-module java.base=${test.src} CarriersTest.java - * @run main/othervm --patch-module java.base=${test.class.path} java.lang.runtime.CarriersTest - */ - -package java.lang.runtime; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import java.util.Arrays; -import java.util.List; - -public class CarriersTest { - public static void main(String[] args) throws Throwable { - primitivesTest(); - primitivesTestLarge(); - limitsTest(); - } - - static void assertTrue(boolean test, String message) { - if (!test) { - throw new RuntimeException(message); - } - } - - static final int MAX_COMPONENTS = 254; - - static void primitivesTest() throws Throwable { - MethodType methodType = - MethodType.methodType(Object.class, byte.class, short.class, - char.class, int.class, long.class, - float.class, double.class, - boolean.class, String.class); - MethodHandle constructor = Carriers.initializingConstructor(methodType); - Object object = (Object)constructor.invokeExact((byte)0xFF, (short)0xFFFF, - 'C', 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFL, - 1.0f / 3.0f, 1.0 / 3.0, - true, "abcde"); - List components = Carriers.components(methodType); - assertTrue((byte)components.get(0).invokeExact(object) == (byte)0xFF, - "primitive byte test failure"); - assertTrue((short)components.get(1).invokeExact(object) == (short)0xFFFF, - "primitive short test failure"); - assertTrue((char)components.get(2).invokeExact(object) == 'C', - "primitive char test failure"); - assertTrue((int)components.get(3).invokeExact(object) == 0xFFFFFFFF, - "primitive int test failure"); - assertTrue((long)components.get(4).invokeExact(object) == 0xFFFFFFFFFFFFFFFFL, - "primitive long test failure"); - assertTrue((float)components.get(5).invokeExact(object) == 1.0f / 3.0f, - "primitive float test failure"); - assertTrue((double)components.get(6).invokeExact(object) == 1.0 / 3.0, - "primitive double test failure"); - assertTrue((boolean)components.get(7).invokeExact(object), - "primitive boolean test failure"); - assertTrue("abcde".equals((String)components.get(8).invokeExact(object)), - "primitive String test failure"); - } - - static void primitivesTestLarge() throws Throwable { - MethodType methodType = - MethodType.methodType(Object.class, byte.class, short.class, - char.class, int.class, long.class, - float.class, double.class, - boolean.class, String.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class, - Object.class, Object.class,Object.class,Object.class - ); - MethodHandle constructor = Carriers.initializingConstructor(methodType); - Object object = (Object)constructor.invokeExact((byte)0xFF, (short)0xFFFF, - 'C', 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFL, - 1.0f / 3.0f, 1.0 / 3.0, - true, "abcde", - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null, - (Object)null, (Object)null, (Object)null, (Object)null - ); - List components = Carriers.components(methodType); - assertTrue((byte)components.get(0).invokeExact(object) == (byte)0xFF, - "large primitive byte test failure"); - assertTrue((short)components.get(1).invokeExact(object) == (short)0xFFFF, - "large primitive short test failure"); - assertTrue((char)components.get(2).invokeExact(object) == 'C', - "large primitive char test failure"); - assertTrue((int)components.get(3).invokeExact(object) == 0xFFFFFFFF, - "large primitive int test failure"); - assertTrue((long)components.get(4).invokeExact(object) == 0xFFFFFFFFFFFFFFFFL, - "large primitive long test failure"); - assertTrue((float)components.get(5).invokeExact(object) == 1.0f / 3.0f, - "large primitive float test failure"); - assertTrue((double)components.get(6).invokeExact(object) == 1.0 / 3.0, - "large primitive double test failure"); - assertTrue((boolean)components.get(7).invokeExact(object), - "large primitive boolean test failure"); - assertTrue("abcde".equals((String)components.get(8).invokeExact(object)), - "large primitive String test failure"); - } - - static void limitsTest() { - boolean passed; - - passed = false; - try { - Class[] ptypes = new Class[MAX_COMPONENTS + 1]; - Arrays.fill(ptypes, Object.class); - MethodType methodType = MethodType.methodType(Object.class, ptypes); - MethodHandle constructor = Carriers.constructor(methodType); - } catch (IllegalArgumentException ex) { - passed = true; - } - - if (!passed) { - throw new RuntimeException("failed to report too many components "); - } - - passed = false; - try { - Class[] ptypes = new Class[MAX_COMPONENTS / 2 + 1]; - Arrays.fill(ptypes, long.class); - MethodType methodType = MethodType.methodType(Object.class, ptypes); - MethodHandle constructor = Carriers.constructor(methodType); - } catch (IllegalArgumentException ex) { - passed = true; - } - - if (!passed) { - throw new RuntimeException("failed to report too many components "); - } - } -} From 77fd103349df59ebd9ab4302b31c2936a3a2ff4e Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 1 Sep 2026 19:57:16 +0000 Subject: [PATCH 182/223] 8388448: VarHandle can set @NullRestricted static field to null Reviewed-by: jvernee --- .../lang/invoke/X-VarHandle.java.template | 3 + .../VarHandles/NullRestrictedValue.java | 28 + .../VarHandleTestAccessBoolean.java | 18 +- .../VarHandles/VarHandleTestAccessByte.java | 18 +- .../VarHandles/VarHandleTestAccessChar.java | 18 +- .../VarHandles/VarHandleTestAccessDouble.java | 18 +- .../VarHandles/VarHandleTestAccessFloat.java | 18 +- .../VarHandles/VarHandleTestAccessInt.java | 18 +- .../VarHandles/VarHandleTestAccessLong.java | 18 +- ...arHandleTestAccessNullRestrictedValue.java | 1659 +++++++++++++ .../VarHandles/VarHandleTestAccessShort.java | 18 +- .../VarHandles/VarHandleTestAccessString.java | 18 +- .../VarHandles/VarHandleTestAccessValue.java | 19 +- ...arHandleTestMethodHandleAccessBoolean.java | 12 +- .../VarHandleTestMethodHandleAccessByte.java | 12 +- .../VarHandleTestMethodHandleAccessChar.java | 12 +- ...VarHandleTestMethodHandleAccessDouble.java | 12 +- .../VarHandleTestMethodHandleAccessFloat.java | 12 +- .../VarHandleTestMethodHandleAccessInt.java | 12 +- .../VarHandleTestMethodHandleAccessLong.java | 12 +- ...MethodHandleAccessNullRestrictedValue.java | 896 +++++++ .../VarHandleTestMethodHandleAccessShort.java | 12 +- ...VarHandleTestMethodHandleAccessString.java | 12 +- .../VarHandleTestMethodHandleAccessValue.java | 13 +- .../VarHandleTestMethodTypeBoolean.java | 12 +- .../VarHandleTestMethodTypeByte.java | 12 +- .../VarHandleTestMethodTypeChar.java | 12 +- .../VarHandleTestMethodTypeDouble.java | 12 +- .../VarHandleTestMethodTypeFloat.java | 12 +- .../VarHandleTestMethodTypeInt.java | 12 +- .../VarHandleTestMethodTypeLong.java | 12 +- ...ndleTestMethodTypeNullRestrictedValue.java | 2071 +++++++++++++++++ .../VarHandleTestMethodTypeShort.java | 12 +- .../VarHandleTestMethodTypeString.java | 12 +- .../VarHandleTestMethodTypeValue.java | 13 +- .../X-VarHandleTestAccess.java.template | 297 ++- ...HandleTestMethodHandleAccess.java.template | 137 +- .../X-VarHandleTestMethodType.java.template | 26 +- .../invoke/VarHandles/generate-vh-tests.sh | 9 +- 39 files changed, 5401 insertions(+), 148 deletions(-) create mode 100644 test/jdk/java/lang/invoke/VarHandles/NullRestrictedValue.java create mode 100644 test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java create mode 100644 test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java create mode 100644 test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template index 7236c3512026..3c446dc52a2e 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template @@ -533,6 +533,9 @@ final class VarHandle$InputType$s { #if[Object] @ForceInline static Object checkCast(FieldStaticReadWrite handle, $type$ value) { + if (handle.nullRestricted && value == null) { + throw new NullPointerException(); + } return handle.fieldType.cast(value); } #end[Object] diff --git a/test/jdk/java/lang/invoke/VarHandles/NullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/NullRestrictedValue.java new file mode 100644 index 000000000000..be4222e08919 --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/NullRestrictedValue.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +value record NullRestrictedValue(byte a, short b) { + static NullRestrictedValue of(byte a, short b) { + return new NullRestrictedValue(a, b); + } +} diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index 4c7a1ba90291..c48b1678fc10 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { static final boolean static_final_v = true; - static boolean static_v; + static boolean static_v = true; - final boolean final_v = true; + final boolean final_v; boolean v; static final boolean static_final_v2 = true; - static boolean static_v2; + static boolean static_v2 = true; - final boolean final_v2 = true; + final boolean final_v2; boolean v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessBoolean extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessBoolean() { + final_v = true; + v = true; + final_v2 = true; + v2 = true; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1415,6 +1422,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index 3a26f75d6cc4..234db06638ed 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { static final byte static_final_v = (byte)0x01; - static byte static_v; + static byte static_v = (byte)0x01; - final byte final_v = (byte)0x01; + final byte final_v; byte v; static final byte static_final_v2 = (byte)0x01; - static byte static_v2; + static byte static_v2 = (byte)0x01; - final byte final_v2 = (byte)0x01; + final byte final_v2; byte v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessByte extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessByte() { + final_v = (byte)0x01; + v = (byte)0x01; + final_v2 = (byte)0x01; + v2 = (byte)0x01; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1452,6 +1459,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index b6e54e3e8582..7d3a57f09872 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { static final char static_final_v = '\u0123'; - static char static_v; + static char static_v = '\u0123'; - final char final_v = '\u0123'; + final char final_v; char v; static final char static_final_v2 = '\u0123'; - static char static_v2; + static char static_v2 = '\u0123'; - final char final_v2 = '\u0123'; + final char final_v2; char v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessChar extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessChar() { + final_v = '\u0123'; + v = '\u0123'; + final_v2 = '\u0123'; + v2 = '\u0123'; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1452,6 +1459,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index 6c4f76d00899..987cad711da2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { static final double static_final_v = 1.0d; - static double static_v; + static double static_v = 1.0d; - final double final_v = 1.0d; + final double final_v; double v; static final double static_final_v2 = 1.0d; - static double static_v2; + static double static_v2 = 1.0d; - final double final_v2 = 1.0d; + final double final_v2; double v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessDouble extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessDouble() { + final_v = 1.0d; + v = 1.0d; + final_v2 = 1.0d; + v2 = 1.0d; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1343,6 +1350,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index c9800f464d07..55f07405138c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { static final float static_final_v = 1.0f; - static float static_v; + static float static_v = 1.0f; - final float final_v = 1.0f; + final float final_v; float v; static final float static_final_v2 = 1.0f; - static float static_v2; + static float static_v2 = 1.0f; - final float final_v2 = 1.0f; + final float final_v2; float v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessFloat extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessFloat() { + final_v = 1.0f; + v = 1.0f; + final_v2 = 1.0f; + v2 = 1.0f; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1343,6 +1350,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index 3f06311988ec..80509800a507 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { static final int static_final_v = 0x01234567; - static int static_v; + static int static_v = 0x01234567; - final int final_v = 0x01234567; + final int final_v; int v; static final int static_final_v2 = 0x01234567; - static int static_v2; + static int static_v2 = 0x01234567; - final int final_v2 = 0x01234567; + final int final_v2; int v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessInt extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessInt() { + final_v = 0x01234567; + v = 0x01234567; + final_v2 = 0x01234567; + v2 = 0x01234567; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1452,6 +1459,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index 7ed1a14bdc8f..ac8db96df9e2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { static final long static_final_v = 0x0123456789ABCDEFL; - static long static_v; + static long static_v = 0x0123456789ABCDEFL; - final long final_v = 0x0123456789ABCDEFL; + final long final_v; long v; static final long static_final_v2 = 0x0123456789ABCDEFL; - static long static_v2; + static long static_v2 = 0x0123456789ABCDEFL; - final long final_v2 = 0x0123456789ABCDEFL; + final long final_v2; long v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessLong extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessLong() { + final_v = 0x0123456789ABCDEFL; + v = 0x0123456789ABCDEFL; + final_v2 = 0x0123456789ABCDEFL; + v2 = 0x0123456789ABCDEFL; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1452,6 +1459,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java new file mode 100644 index 000000000000..db3743b31e41 --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java @@ -0,0 +1,1659 @@ +/* + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// -- This file was mechanically generated: Do not edit! -- // + +/* + * @test + * @enablePreview + * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value + * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessNullRestrictedValue + * + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations + * to hit compilation thresholds + * + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessNullRestrictedValue + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessNullRestrictedValue + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestAccessNullRestrictedValue + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class VarHandleTestAccessNullRestrictedValue extends VarHandleBaseTest { + static final @NullRestricted NullRestrictedValue static_final_v = NullRestrictedValue.of((byte)20,(short)1854); + + static @NullRestricted NullRestrictedValue static_v = NullRestrictedValue.of((byte)20,(short)1854); + + final @NullRestricted NullRestrictedValue final_v; + + @NullRestricted NullRestrictedValue v; + + static final @NullRestricted NullRestrictedValue static_final_v2 = NullRestrictedValue.of((byte)20,(short)1854); + + static @NullRestricted NullRestrictedValue static_v2 = NullRestrictedValue.of((byte)20,(short)1854); + + final @NullRestricted NullRestrictedValue final_v2; + + @NullRestricted NullRestrictedValue v2; + + VarHandle vhFinalField; + + VarHandle vhField; + + VarHandle vhStaticField; + + VarHandle vhStaticFinalField; + + VarHandle vhArray; + + VarHandle vhArrayObject; + + public VarHandleTestAccessNullRestrictedValue() { + final_v = NullRestrictedValue.of((byte)20,(short)1854); + v = NullRestrictedValue.of((byte)20,(short)1854); + final_v2 = NullRestrictedValue.of((byte)20,(short)1854); + v2 = NullRestrictedValue.of((byte)20,(short)1854); + super(); + } + + VarHandle[] allocate(boolean same) { + List vhs = new ArrayList<>(); + + String postfix = same ? "" : "2"; + VarHandle vh; + try { + vh = MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "final_v" + postfix, NullRestrictedValue.class); + vhs.add(vh); + + vh = MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "v" + postfix, NullRestrictedValue.class); + vhs.add(vh); + + vh = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_final_v" + postfix, NullRestrictedValue.class); + vhs.add(vh); + + vh = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_v" + postfix, NullRestrictedValue.class); + vhs.add(vh); + + if (same) { + vh = MethodHandles.arrayElementVarHandle(NullRestrictedValue[].class); + } + else { + vh = MethodHandles.arrayElementVarHandle(String[].class); + } + vhs.add(vh); + } catch (Exception e) { + throw new InternalError(e); + } + return vhs.toArray(new VarHandle[0]); + } + + @BeforeAll + public void setup() throws Exception { + vhFinalField = MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "final_v", NullRestrictedValue.class); + + vhField = MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "v", NullRestrictedValue.class); + + vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_final_v", NullRestrictedValue.class); + + vhStaticField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_v", NullRestrictedValue.class); + + vhArray = MethodHandles.arrayElementVarHandle(NullRestrictedValue[].class); + vhArrayObject = MethodHandles.arrayElementVarHandle(Object[].class); + } + + public Object[][] varHandlesProvider() throws Exception { + List vhs = new ArrayList<>(); + vhs.add(vhField); + vhs.add(vhStaticField); + vhs.add(vhArray); + + return vhs.stream().map(tc -> new Object[]{tc}).toArray(Object[][]::new); + } + + @Test + public void testEquals() { + VarHandle[] vhs1 = allocate(true); + VarHandle[] vhs2 = allocate(true); + + for (int i = 0; i < vhs1.length; i++) { + for (int j = 0; j < vhs1.length; j++) { + if (i != j) { + assertNotEquals(vhs1[i], vhs1[j]); + assertNotEquals(vhs1[i], vhs2[j]); + } + } + } + + VarHandle[] vhs3 = allocate(false); + for (int i = 0; i < vhs1.length; i++) { + assertNotEquals(vhs1[i], vhs3[i]); + } + } + + @ParameterizedTest + @MethodSource("varHandlesProvider") + public void testIsAccessModeSupported(VarHandle vh) { + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_VOLATILE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_VOLATILE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_ACQUIRE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_RELEASE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_OPAQUE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.SET_OPAQUE)); + + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET_ACQUIRE)); + assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET_RELEASE)); + + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD_ACQUIRE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_ADD_RELEASE)); + + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_OR)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_AND)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE)); + assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)); + } + + public Object[][] typesProvider() throws Exception { + List types = new ArrayList<>(); + types.add(new Object[] {vhField, Arrays.asList(VarHandleTestAccessNullRestrictedValue.class)}); + types.add(new Object[] {vhStaticField, Arrays.asList()}); + types.add(new Object[] {vhArray, Arrays.asList(NullRestrictedValue[].class, int.class)}); + + return types.stream().toArray(Object[][]::new); + } + + @ParameterizedTest + @MethodSource("typesProvider") + public void testTypes(VarHandle vh, List> pts) { + assertEquals(NullRestrictedValue.class, vh.varType()); + + assertEquals(pts, vh.coordinateTypes()); + + testTypes(vh); + } + + @Test + public void testLookupInstanceToStatic() { + checkIAE("Lookup of static final field to instance final field", () -> { + MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "final_v", NullRestrictedValue.class); + }); + + checkIAE("Lookup of static field to instance field", () -> { + MethodHandles.lookup().findStaticVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "v", NullRestrictedValue.class); + }); + } + + @Test + public void testLookupStaticToInstance() { + checkIAE("Lookup of instance final field to static final field", () -> { + MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_final_v", NullRestrictedValue.class); + }); + + checkIAE("Lookup of instance field to static field", () -> { + vhStaticField = MethodHandles.lookup().findVarHandle( + VarHandleTestAccessNullRestrictedValue.class, "static_v", NullRestrictedValue.class); + }); + } + + public Object[][] accessTestCaseProvider() throws Exception { + List> cases = new ArrayList<>(); + + cases.add(new VarHandleAccessTestCase("Instance final field", + vhFinalField, vh -> testInstanceFinalField(this, vh))); + cases.add(new VarHandleAccessTestCase("Instance final field unsupported", + vhFinalField, vh -> testInstanceFinalFieldUnsupported(this, vh), + false)); + + cases.add(new VarHandleAccessTestCase("Static final field", + vhStaticFinalField, VarHandleTestAccessNullRestrictedValue::testStaticFinalField)); + cases.add(new VarHandleAccessTestCase("Static final field unsupported", + vhStaticFinalField, VarHandleTestAccessNullRestrictedValue::testStaticFinalFieldUnsupported, + false)); + + cases.add(new VarHandleAccessTestCase("Instance field", + vhField, vh -> testInstanceField(this, vh))); + cases.add(new VarHandleAccessTestCase("Instance field unsupported", + vhField, vh -> testInstanceFieldUnsupported(this, vh), + false)); + cases.add(new VarHandleAccessTestCase("Instance field null pointer exception", + vhField, vh -> testInstanceFieldNullPointerException(this, vh), + false)); + + cases.add(new VarHandleAccessTestCase("Static field", + vhStaticField, VarHandleTestAccessNullRestrictedValue::testStaticField)); + cases.add(new VarHandleAccessTestCase("Static field unsupported", + vhStaticField, VarHandleTestAccessNullRestrictedValue::testStaticFieldUnsupported, + false)); + cases.add(new VarHandleAccessTestCase("Static field null pointer exception", + vhStaticField, VarHandleTestAccessNullRestrictedValue::testStaticFieldNullPointerException, + false)); + + cases.add(new VarHandleAccessTestCase("Array", + vhArray, VarHandleTestAccessNullRestrictedValue::testArray)); + cases.add(new VarHandleAccessTestCase("Array Object[]", + vhArrayObject, VarHandleTestAccessNullRestrictedValue::testArray)); + cases.add(new VarHandleAccessTestCase("Array unsupported", + vhArray, VarHandleTestAccessNullRestrictedValue::testArrayUnsupported, + false)); + cases.add(new VarHandleAccessTestCase("Array index out of bounds", + vhArray, VarHandleTestAccessNullRestrictedValue::testArrayIndexOutOfBounds, + false)); + cases.add(new VarHandleAccessTestCase("Array store exception", + vhArrayObject, VarHandleTestAccessNullRestrictedValue::testArrayStoreException, + false)); + cases.add(new VarHandleAccessTestCase("Array null pointer exception", + vhArrayObject, VarHandleTestAccessNullRestrictedValue::testArrayNullPointerException, + false)); + // Work around issue with jtreg summary reporting which truncates + // the String result of Object.toString to 30 characters, hence + // the first dummy argument + return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); + } + + @ParameterizedTest + @MethodSource("accessTestCaseProvider") + public void testAccess(String desc, AccessTestCase atc) throws Throwable { + T t = atc.get(); + int iters = atc.requiresLoop() ? ITERS : 1; + for (int c = 0; c < iters; c++) { + atc.testAccess(t); + } + } + + static void testInstanceFinalField(VarHandleTestAccessNullRestrictedValue recv, VarHandle vh) { + // Plain + { + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "get NullRestrictedValue value"); + } + + + // Volatile + { + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getVolatile NullRestrictedValue value"); + } + + // Lazy + { + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getRelease NullRestrictedValue value"); + } + + // Opaque + { + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getOpaque NullRestrictedValue value"); + } + } + + static void testInstanceFinalFieldUnsupported(VarHandleTestAccessNullRestrictedValue recv, VarHandle vh) { + checkUOE(() -> { + vh.set(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setVolatile(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setRelease(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setOpaque(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAdd(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOr(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAnd(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXor(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + + static void testStaticFinalField(VarHandle vh) { + // Plain + { + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "get NullRestrictedValue value"); + } + + + // Volatile + { + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getVolatile NullRestrictedValue value"); + } + + // Lazy + { + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getRelease NullRestrictedValue value"); + } + + // Opaque + { + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getOpaque NullRestrictedValue value"); + } + } + + static void testStaticFinalFieldUnsupported(VarHandle vh) { + checkUOE(() -> { + vh.set(NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setVolatile(NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setRelease(NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkUOE(() -> { + vh.setOpaque(NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAdd(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOr(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAnd(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXor(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + + static void testInstanceField(VarHandleTestAccessNullRestrictedValue recv, VarHandle vh) { + // Plain + { + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "set NullRestrictedValue value"); + } + + + // Volatile + { + vh.setVolatile(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + vh.setRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + vh.setOpaque(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue value"); + } + + { + boolean success = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSet(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + { + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetAcquire(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + { + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetRelease(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + + + } + + static void testInstanceFieldUnsupported(VarHandleTestAccessNullRestrictedValue recv, VarHandle vh) { + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAdd(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOr(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAnd(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXor(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + + static void testStaticField(VarHandle vh) { + // Plain + { + vh.set(NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "set NullRestrictedValue value"); + } + + + // Volatile + { + vh.setVolatile(NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + vh.setRelease(NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + vh.setOpaque(NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + vh.set(NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSet(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSet(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + vh.set(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSet(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + { + vh.set(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetAcquire(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + { + vh.set(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetRelease(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + + + } + + static void testStaticFieldUnsupported(VarHandle vh) { + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAdd(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOr(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAnd(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXor(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + + static void testArray(VarHandle vh) { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + for (int i = 0; i < array.length; i++) { + // Plain + { + vh.set(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "get NullRestrictedValue value"); + } + + + // Volatile + { + vh.setVolatile(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + vh.setRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + vh.setOpaque(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + vh.set(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = vh.compareAndSet(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = vh.compareAndSet(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetPlain(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = vh.weakCompareAndSetPlain(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetAcquire(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetAcquire(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSetRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSetRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = vh.weakCompareAndSet(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue"); + } + + { + boolean success = vh.weakCompareAndSet(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + vh.set(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSet(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + { + vh.set(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetAcquire(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + { + vh.set(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetRelease(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + + + } + } + + static void testArrayUnsupported(VarHandle vh) { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + int i = 0; + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAdd(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndAddRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOr(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseOrRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAnd(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseAndRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXor(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorAcquire(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkUOE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndBitwiseXorRelease(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) { + final int ci = i; + + checkAIOOBE(() -> { + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, ci); + }); + + checkAIOOBE(() -> { + vh.set(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(array, ci); + }); + + checkAIOOBE(() -> { + vh.setVolatile(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(array, ci); + }); + + checkAIOOBE(() -> { + vh.setRelease(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(array, ci); + }); + + checkAIOOBE(() -> { + vh.setOpaque(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + boolean r = vh.compareAndSet(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchange(array, ci, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, ci, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue r = (NullRestrictedValue) vh.compareAndExchangeRelease(array, ci, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + boolean r = vh.weakCompareAndSetPlain(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkAIOOBE(() -> { + boolean r = vh.weakCompareAndSet(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkAIOOBE(() -> { + boolean r = vh.weakCompareAndSetAcquire(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkAIOOBE(() -> { + boolean r = vh.weakCompareAndSetRelease(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSet(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetAcquire(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + checkAIOOBE(() -> { + NullRestrictedValue o = (NullRestrictedValue) vh.getAndSetRelease(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + + + } + } + + static void testArrayStoreException(VarHandle vh) throws Throwable { + Object[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + Arrays.fill(array, NullRestrictedValue.of((byte)20,(short)1854)); + Object value = new Object(); + + // Set + checkASE(() -> { + vh.set(array, 0, value); + }); + + // SetVolatile + checkASE(() -> { + vh.setVolatile(array, 0, value); + }); + + // SetOpaque + checkASE(() -> { + vh.setOpaque(array, 0, value); + }); + + // SetRelease + checkASE(() -> { + vh.setRelease(array, 0, value); + }); + + // CompareAndSet + checkASE(() -> { // receiver reference class + boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSet + checkASE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetVolatile + checkASE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetAcquire + checkASE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetRelease + checkASE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchange + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeAcquire + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeRelease + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // GetAndSet + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, value); + }); + + // GetAndSetAcquire + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, value); + }); + + // GetAndSetRelease + checkASE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, value); + }); + } + + static void testInstanceFieldNullPointerException(VarHandleTestAccessNullRestrictedValue recv, VarHandle vh) throws Throwable { + NullRestrictedValue value = null; + + // Set + checkNPE(() -> { + vh.set(recv, value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(recv, value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(recv, value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(recv, value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(recv, value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(recv, value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(recv, value); + }); + } + + static void testStaticFieldNullPointerException(VarHandle vh) throws Throwable { + NullRestrictedValue value = null; + + // Set + checkNPE(() -> { + vh.set(value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(value); + }); + } + + static void testArrayNullPointerException(VarHandle vh) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue value = null; + + // Set + checkNPE(() -> { + vh.set(array, 0, value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(array, 0, value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(array, 0, value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(array, 0, value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, value); + }); + } +} + diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index f3f5401584df..1da5fe5018b2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { static final short static_final_v = (short)0x0123; - static short static_v; + static short static_v = (short)0x0123; - final short final_v = (short)0x0123; + final short final_v; short v; static final short static_final_v2 = (short)0x0123; - static short static_v2; + static short static_v2 = (short)0x0123; - final short final_v2 = (short)0x0123; + final short final_v2; short v2; @@ -76,6 +76,13 @@ public class VarHandleTestAccessShort extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestAccessShort() { + final_v = (short)0x0123; + v = (short)0x0123; + final_v2 = (short)0x0123; + v2 = (short)0x0123; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -1452,6 +1459,5 @@ static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { }); } } - } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 764145624855..614528d294b4 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,17 +52,17 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { static final String static_final_v = "foo"; - static String static_v; + static String static_v = "foo"; - final String final_v = "foo"; + final String final_v; String v; static final String static_final_v2 = "foo"; - static String static_v2; + static String static_v2 = "foo"; - final String final_v2 = "foo"; + final String final_v2; String v2; @@ -78,6 +78,14 @@ public class VarHandleTestAccessString extends VarHandleBaseTest { VarHandle vhArrayObject; + public VarHandleTestAccessString() { + final_v = "foo"; + v = "foo"; + final_v2 = "foo"; + v2 = "foo"; + super(); + } + VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java index a2aec4d3dbc9..7b974a3bed90 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @test * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessValue * * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations @@ -54,17 +55,17 @@ public class VarHandleTestAccessValue extends VarHandleBaseTest { static final Value static_final_v = Value.getInstance(10); - static Value static_v; + static Value static_v = Value.getInstance(10); - final Value final_v = Value.getInstance(10); + final Value final_v; Value v; static final Value static_final_v2 = Value.getInstance(10); - static Value static_v2; + static Value static_v2 = Value.getInstance(10); - final Value final_v2 = Value.getInstance(10); + final Value final_v2; Value v2; @@ -80,6 +81,14 @@ public class VarHandleTestAccessValue extends VarHandleBaseTest { VarHandle vhArrayObject; + public VarHandleTestAccessValue() { + final_v = Value.getInstance(10); + v = Value.getInstance(10); + final_v2 = Value.getInstance(10); + v2 = Value.getInstance(10); + super(); + } + VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java index 5c1eba506e90..88535d597f5a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { static final boolean static_final_v = true; - static boolean static_v; + static boolean static_v = true; - final boolean final_v = true; + final boolean final_v; boolean v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessBoolean extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessBoolean() { + final_v = true; + v = true; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java index cd54a8e16d55..d97875247404 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { static final byte static_final_v = (byte)0x01; - static byte static_v; + static byte static_v = (byte)0x01; - final byte final_v = (byte)0x01; + final byte final_v; byte v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessByte extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessByte() { + final_v = (byte)0x01; + v = (byte)0x01; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java index e67de6cf7a44..f9d714f3cd0a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { static final char static_final_v = '\u0123'; - static char static_v; + static char static_v = '\u0123'; - final char final_v = '\u0123'; + final char final_v; char v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessChar extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessChar() { + final_v = '\u0123'; + v = '\u0123'; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java index d944c4316c26..120897a9352c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { static final double static_final_v = 1.0d; - static double static_v; + static double static_v = 1.0d; - final double final_v = 1.0d; + final double final_v; double v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessDouble extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessDouble() { + final_v = 1.0d; + v = 1.0d; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java index 2b1beed2c013..acdf5d81cec9 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { static final float static_final_v = 1.0f; - static float static_v; + static float static_v = 1.0f; - final float final_v = 1.0f; + final float final_v; float v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessFloat extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessFloat() { + final_v = 1.0f; + v = 1.0f; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java index 5dc48bc22f97..8960ae124079 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { static final int static_final_v = 0x01234567; - static int static_v; + static int static_v = 0x01234567; - final int final_v = 0x01234567; + final int final_v; int v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessInt extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessInt() { + final_v = 0x01234567; + v = 0x01234567; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java index 0950470c8797..cc6f2e729891 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { static final long static_final_v = 0x0123456789ABCDEFL; - static long static_v; + static long static_v = 0x0123456789ABCDEFL; - final long final_v = 0x0123456789ABCDEFL; + final long final_v; long v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessLong extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessLong() { + final_v = 0x0123456789ABCDEFL; + v = 0x0123456789ABCDEFL; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java new file mode 100644 index 000000000000..c9fc8fc1b6a3 --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java @@ -0,0 +1,896 @@ +/* + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// -- This file was mechanically generated: Do not edit! -- // + +/* + * @test + * @enablePreview + * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations + * to hit compilation thresholds + * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessNullRestrictedValue + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.List; + +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class VarHandleTestMethodHandleAccessNullRestrictedValue extends VarHandleBaseTest { + static final @NullRestricted NullRestrictedValue static_final_v = NullRestrictedValue.of((byte)20,(short)1854); + + static @NullRestricted NullRestrictedValue static_v = NullRestrictedValue.of((byte)20,(short)1854); + + final @NullRestricted NullRestrictedValue final_v; + + @NullRestricted NullRestrictedValue v; + + VarHandle vhFinalField; + + VarHandle vhField; + + VarHandle vhStaticField; + + VarHandle vhStaticFinalField; + + VarHandle vhArray; + + public VarHandleTestMethodHandleAccessNullRestrictedValue() { + final_v = NullRestrictedValue.of((byte)20,(short)1854); + v = NullRestrictedValue.of((byte)20,(short)1854); + super(); + } + + @BeforeAll + public void setup() throws Exception { + vhFinalField = MethodHandles.lookup().findVarHandle( + VarHandleTestMethodHandleAccessNullRestrictedValue.class, "final_v", NullRestrictedValue.class); + + vhField = MethodHandles.lookup().findVarHandle( + VarHandleTestMethodHandleAccessNullRestrictedValue.class, "v", NullRestrictedValue.class); + + vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestMethodHandleAccessNullRestrictedValue.class, "static_final_v", NullRestrictedValue.class); + + vhStaticField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestMethodHandleAccessNullRestrictedValue.class, "static_v", NullRestrictedValue.class); + + vhArray = MethodHandles.arrayElementVarHandle(NullRestrictedValue[].class); + } + + public Object[][] accessTestCaseProvider() throws Exception { + List> cases = new ArrayList<>(); + + for (VarHandleToMethodHandle f : VarHandleToMethodHandle.values()) { + cases.add(new MethodHandleAccessTestCase("Instance field", + vhField, f, hs -> testInstanceField(this, hs))); + cases.add(new MethodHandleAccessTestCase("Instance field unsupported", + vhField, f, hs -> testInstanceFieldUnsupported(this, hs), + false)); + cases.add(new MethodHandleAccessTestCase("Instance field null pointer exception", + vhField, f, hs -> testInstanceFieldNullPointerException(this, hs), + false)); + + cases.add(new MethodHandleAccessTestCase("Static field", + vhStaticField, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testStaticField)); + cases.add(new MethodHandleAccessTestCase("Static field unsupported", + vhStaticField, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testStaticFieldUnsupported, + false)); + cases.add(new MethodHandleAccessTestCase("Static field null pointer exception", + vhStaticField, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testStaticFieldNullPointerException, + false)); + + cases.add(new MethodHandleAccessTestCase("Array", + vhArray, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testArray)); + cases.add(new MethodHandleAccessTestCase("Array unsupported", + vhArray, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testArrayUnsupported, + false)); + cases.add(new MethodHandleAccessTestCase("Array index out of bounds", + vhArray, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testArrayIndexOutOfBounds, + false)); + cases.add(new MethodHandleAccessTestCase("Array null pointer exception", + vhArray, f, VarHandleTestMethodHandleAccessNullRestrictedValue::testArrayNullPointerException, + false)); + } + + // Work around issue with jtreg summary reporting which truncates + // the String result of Object.toString to 30 characters, hence + // the first dummy argument + return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); + } + + @ParameterizedTest + @MethodSource("accessTestCaseProvider") + public void testAccess(String desc, AccessTestCase atc) throws Throwable { + T t = atc.get(); + int iters = atc.requiresLoop() ? ITERS : 1; + for (int c = 0; c < iters; c++) { + atc.testAccess(t); + } + } + + static void testInstanceField(VarHandleTestMethodHandleAccessNullRestrictedValue recv, Handles hs) throws Throwable { + // Plain + { + hs.get(TestAccessMode.SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "set NullRestrictedValue value"); + } + + + // Volatile + { + hs.get(TestAccessMode.SET_VOLATILE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + hs.get(TestAccessMode.SET_RELEASE).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + hs.get(TestAccessMode.SET_OPAQUE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + hs.get(TestAccessMode.SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); + } + + { + boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + + } + + static void testInstanceFieldUnsupported(VarHandleTestMethodHandleAccessNullRestrictedValue recv, Handles hs) throws Throwable { + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) { + checkUOE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_BITWISE)) { + checkUOE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + } + + + static void testStaticField(Handles hs) throws Throwable { + // Plain + { + hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "set NullRestrictedValue value"); + } + + + // Volatile + { + hs.get(TestAccessMode.SET_VOLATILE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + hs.get(TestAccessMode.SET_RELEASE).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + hs.get(TestAccessMode.SET_OPAQUE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetRe NullRestrictedValue value"); + } + + // Compare set and get + { + hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + // Compare set and get + { + hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + + + } + + static void testStaticFieldUnsupported(Handles hs) throws Throwable { + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) { + checkUOE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_BITWISE)) { + checkUOE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + } + + + static void testArray(Handles hs) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + for (int i = 0; i < array.length; i++) { + // Plain + { + hs.get(TestAccessMode.SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "get NullRestrictedValue value"); + } + + + // Volatile + { + hs.get(TestAccessMode.SET_VOLATILE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_VOLATILE).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setVolatile NullRestrictedValue value"); + } + + // Lazy + { + hs.get(TestAccessMode.SET_RELEASE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_ACQUIRE).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "setRelease NullRestrictedValue value"); + } + + // Opaque + { + hs.get(TestAccessMode.SET_OPAQUE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET_OPAQUE).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "setOpaque NullRestrictedValue value"); + } + + hs.get(TestAccessMode.SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + // Compare + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, true, "success compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndSet NullRestrictedValue value"); + } + + { + boolean r = (boolean) hs.get(TestAccessMode.COMPARE_AND_SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, false, "failing compareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndSet NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchange NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchange NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "success compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "failing compareAndExchangeAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing compareAndExchangeAcquire NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + assertEquals(r, NullRestrictedValue.of((byte)-42,(short)1854), "success compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success compareAndExchangeRelease NullRestrictedValue value"); + } + + { + NullRestrictedValue r = (NullRestrictedValue) hs.get(TestAccessMode.COMPARE_AND_EXCHANGE_RELEASE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(r, NullRestrictedValue.of((byte)20,(short)1854), "failing compareAndExchangeRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing compareAndExchangeRelease NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetPlain NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetPlain NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSetAcquire NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "success weakCompareAndSetRelease NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + } + + { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = (boolean) mh.invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + if (!success) weakDelay(); + } + assertEquals(success, true, "success weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "success weakCompareAndSet NullRestrictedValue"); + } + + { + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); + } + + // Compare set and get + { + hs.get(TestAccessMode.SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(array, i, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + + + } + } + + static void testArrayUnsupported(Handles hs) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + final int i = 0; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_ADD)) { + checkUOE(am, () -> { + NullRestrictedValue o = (NullRestrictedValue) hs.get(am).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_BITWISE)) { + checkUOE(am, () -> { + NullRestrictedValue o = (NullRestrictedValue) hs.get(am).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + } + + static void testArrayIndexOutOfBounds(Handles hs) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + + for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) { + final int ci = i; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) { + checkAIOOBE(am, () -> { + NullRestrictedValue x = (NullRestrictedValue) hs.get(am).invokeExact(array, ci); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkAIOOBE(am, () -> { + hs.get(am).invokeExact(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkAIOOBE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(array, ci, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)-42,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkAIOOBE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(array, ci, NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkAIOOBE(am, () -> { + NullRestrictedValue o = (NullRestrictedValue) hs.get(am).invokeExact(array, ci, NullRestrictedValue.of((byte)20,(short)1854)); + }); + } + + + } + } + + static void testInstanceFieldNullPointerException(VarHandleTestMethodHandleAccessNullRestrictedValue recv, Handles hs) throws Throwable { + NullRestrictedValue value = null; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(recv, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(recv, value); + }); + } + } + + static void testStaticFieldNullPointerException(Handles hs) throws Throwable { + NullRestrictedValue value = null; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(value); + }); + } + } + + static void testArrayNullPointerException(Handles hs) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue value = null; + + final int i = 0; + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(array, i, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + NullRestrictedValue r = (NullRestrictedValue) hs.get(am).invokeExact(array, i, value); + }); + } + } +} + diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java index 337367d8147c..c5db745cd280 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { static final short static_final_v = (short)0x0123; - static short static_v; + static short static_v = (short)0x0123; - final short final_v = (short)0x0123; + final short final_v; short v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessShort extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessShort() { + final_v = (short)0x0123; + v = (short)0x0123; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java index 13245291af94..f19fc8f631a4 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,9 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { static final String static_final_v = "foo"; - static String static_v; + static String static_v = "foo"; - final String final_v = "foo"; + final String final_v; String v; @@ -62,6 +62,12 @@ public class VarHandleTestMethodHandleAccessString extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessString() { + final_v = "foo"; + v = "foo"; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java index 64cf0326d5f1..32846afa5230 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @test * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessValue @@ -48,9 +49,9 @@ public class VarHandleTestMethodHandleAccessValue extends VarHandleBaseTest { static final Value static_final_v = Value.getInstance(10); - static Value static_v; + static Value static_v = Value.getInstance(10); - final Value final_v = Value.getInstance(10); + final Value final_v; Value v; @@ -64,6 +65,12 @@ public class VarHandleTestMethodHandleAccessValue extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccessValue() { + final_v = Value.getInstance(10); + v = Value.getInstance(10); + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java index a413029d87d6..d4413f0ab961 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { static boolean static_v = true; - final boolean final_v = true; + final boolean final_v; - boolean v = true; + boolean v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeBoolean extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeBoolean() { + final_v = true; + v = true; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java index 40ce205ecb7b..2abb22a65ae6 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { static byte static_v = (byte)0x01; - final byte final_v = (byte)0x01; + final byte final_v; - byte v = (byte)0x01; + byte v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeByte extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeByte() { + final_v = (byte)0x01; + v = (byte)0x01; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java index eb4d91692fd8..4eaf3d5c69fd 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { static char static_v = '\u0123'; - final char final_v = '\u0123'; + final char final_v; - char v = '\u0123'; + char v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeChar extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeChar() { + final_v = '\u0123'; + v = '\u0123'; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java index c6687ce08c33..995b7008a468 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { static double static_v = 1.0d; - final double final_v = 1.0d; + final double final_v; - double v = 1.0d; + double v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeDouble extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeDouble() { + final_v = 1.0d; + v = 1.0d; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java index 35f0601a9eed..5ab921168859 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { static float static_v = 1.0f; - final float final_v = 1.0f; + final float final_v; - float v = 1.0f; + float v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeFloat extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeFloat() { + final_v = 1.0f; + v = 1.0f; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java index 28e3be315829..fd8745edbf01 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { static int static_v = 0x01234567; - final int final_v = 0x01234567; + final int final_v; - int v = 0x01234567; + int v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeInt extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeInt() { + final_v = 0x01234567; + v = 0x01234567; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java index 69c6ee4c6925..3a7acef97b4a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { static long static_v = 0x0123456789ABCDEFL; - final long final_v = 0x0123456789ABCDEFL; + final long final_v; - long v = 0x0123456789ABCDEFL; + long v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeLong extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeLong() { + final_v = 0x0123456789ABCDEFL; + v = 0x0123456789ABCDEFL; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java new file mode 100644 index 000000000000..900e58f0545d --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java @@ -0,0 +1,2071 @@ +/* + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// -- This file was mechanically generated: Do not edit! -- // + +/* + * @test + * @bug 8156486 + * @enablePreview + * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value + * @run junit/othervm VarHandleTestMethodTypeNullRestrictedValue + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeNullRestrictedValue + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeNullRestrictedValue + * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeNullRestrictedValue + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static java.lang.invoke.MethodType.*; + +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class VarHandleTestMethodTypeNullRestrictedValue extends VarHandleBaseTest { + static final @NullRestricted NullRestrictedValue static_final_v = NullRestrictedValue.of((byte)20,(short)1854); + + static @NullRestricted NullRestrictedValue static_v = NullRestrictedValue.of((byte)20,(short)1854); + + final @NullRestricted NullRestrictedValue final_v; + + @NullRestricted NullRestrictedValue v; + + VarHandle vhFinalField; + + VarHandle vhField; + + VarHandle vhStaticField; + + VarHandle vhStaticFinalField; + + VarHandle vhArray; + + public VarHandleTestMethodTypeNullRestrictedValue() { + final_v = NullRestrictedValue.of((byte)20,(short)1854); + v = NullRestrictedValue.of((byte)20,(short)1854); + super(); + } + + @BeforeAll + public void setup() throws Exception { + vhFinalField = MethodHandles.lookup().findVarHandle( + VarHandleTestMethodTypeNullRestrictedValue.class, "final_v", NullRestrictedValue.class); + + vhField = MethodHandles.lookup().findVarHandle( + VarHandleTestMethodTypeNullRestrictedValue.class, "v", NullRestrictedValue.class); + + vhStaticFinalField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestMethodTypeNullRestrictedValue.class, "static_final_v", NullRestrictedValue.class); + + vhStaticField = MethodHandles.lookup().findStaticVarHandle( + VarHandleTestMethodTypeNullRestrictedValue.class, "static_v", NullRestrictedValue.class); + + vhArray = MethodHandles.arrayElementVarHandle(NullRestrictedValue[].class); + } + + public Object[][] accessTestCaseProvider() throws Exception { + List> cases = new ArrayList<>(); + + cases.add(new VarHandleAccessTestCase("Instance field", + vhField, vh -> testInstanceFieldWrongMethodType(this, vh), + false)); + + cases.add(new VarHandleAccessTestCase("Static field", + vhStaticField, VarHandleTestMethodTypeNullRestrictedValue::testStaticFieldWrongMethodType, + false)); + + cases.add(new VarHandleAccessTestCase("Array", + vhArray, VarHandleTestMethodTypeNullRestrictedValue::testArrayWrongMethodType, + false)); + + for (VarHandleToMethodHandle f : VarHandleToMethodHandle.values()) { + cases.add(new MethodHandleAccessTestCase("Instance field", + vhField, f, hs -> testInstanceFieldWrongMethodType(this, hs), + false)); + + cases.add(new MethodHandleAccessTestCase("Static field", + vhStaticField, f, VarHandleTestMethodTypeNullRestrictedValue::testStaticFieldWrongMethodType, + false)); + + cases.add(new MethodHandleAccessTestCase("Array", + vhArray, f, VarHandleTestMethodTypeNullRestrictedValue::testArrayWrongMethodType, + false)); + } + // Work around issue with jtreg summary reporting which truncates + // the String result of Object.toString to 30 characters, hence + // the first dummy argument + return cases.stream().map(tc -> new Object[]{tc.toString(), tc}).toArray(Object[][]::new); + } + + @ParameterizedTest + @MethodSource("accessTestCaseProvider") + public void testAccess(String desc, AccessTestCase atc) throws Throwable { + T t = atc.get(); + int iters = atc.requiresLoop() ? ITERS : 1; + for (int c = 0; c < iters; c++) { + atc.testAccess(t); + } + } + + static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrictedValue recv, VarHandle vh) throws Throwable { + // Get + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.get(null); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.get(Void.class); + }); + checkWMTE(() -> { // receiver primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.get(0); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.get(recv); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.get(recv); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.get(recv, Void.class); + }); + + + // Set + // Incorrect argument types + checkNPE(() -> { // null receiver + vh.set(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + vh.set(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.set(recv, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.set(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.set(); + }); + checkWMTE(() -> { // > + vh.set(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(null); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(Void.class); + }); + checkWMTE(() -> { // receiver primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(0); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getVolatile(recv); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getVolatile(recv); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(recv, Void.class); + }); + + + // SetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + vh.setVolatile(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + vh.setVolatile(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setVolatile(recv, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setVolatile(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setVolatile(); + }); + checkWMTE(() -> { // > + vh.setVolatile(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetOpaque + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(null); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(Void.class); + }); + checkWMTE(() -> { // receiver primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(0); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getOpaque(recv); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getOpaque(recv); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(recv, Void.class); + }); + + + // SetOpaque + // Incorrect argument types + checkNPE(() -> { // null receiver + vh.setOpaque(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + vh.setOpaque(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setOpaque(recv, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setOpaque(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setOpaque(); + }); + checkWMTE(() -> { // > + vh.setOpaque(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(null); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(Void.class); + }); + checkWMTE(() -> { // receiver primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(0); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getAcquire(recv); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAcquire(recv); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(recv, Void.class); + }); + + + // SetRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + vh.setRelease(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + vh.setRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setRelease(recv, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setRelease(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setRelease(); + }); + checkWMTE(() -> { // > + vh.setRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndSet + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.compareAndSet(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.compareAndSet(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.compareAndSet(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.compareAndSet(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.compareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSet + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetPlain(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetPlain(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetPlain(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetPlain(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSet(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSet(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSet(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetAcquire(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetAcquire(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetAcquire(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetAcquire(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetRelease(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetRelease(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetRelease(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetRelease(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchange + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSet + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(recv, Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + // GetAndSetAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(recv, Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + // GetAndSetRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(recv, Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + } + + static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrictedValue recv, Handles hs) throws Throwable { + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) { + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class)). + invokeExact((VarHandleTestMethodTypeNullRestrictedValue) null); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class)). + invokeExact(Void.class); + }); + checkWMTE(() -> { // receiver primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class)). + invokeExact(0); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void x = (Void) hs.get(am, methodType(Void.class, VarHandleTestMethodTypeNullRestrictedValue.class)). + invokeExact(recv); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class)). + invokeExact(recv); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class)). + invokeExact(recv, Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + // Incorrect argument types + checkNPE(() -> { // null receiver + hs.get(am, methodType(void.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((VarHandleTestMethodTypeNullRestrictedValue) null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + hs.get(am, methodType(void.class, Class.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // value reference class + hs.get(am, methodType(void.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class)). + invokeExact(recv, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + hs.get(am, methodType(void.class, int.class, NullRestrictedValue.class)). + invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + hs.get(am, methodType(void.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + hs.get(am, methodType(void.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((VarHandleTestMethodTypeNullRestrictedValue) null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, Class.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // expected reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class, NullRestrictedValue.class)). + invokeExact(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = (boolean) hs.get(am, methodType(boolean.class, int.class , NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = (boolean) hs.get(am, methodType(boolean.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + boolean r = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((VarHandleTestMethodTypeNullRestrictedValue) null, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class, NullRestrictedValue.class)). + invokeExact(recv, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class , NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, VarHandleTestMethodTypeNullRestrictedValue.class , NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class , NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((VarHandleTestMethodTypeNullRestrictedValue) null, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class)). + invokeExact(recv, Void.class); + }); + checkWMTE(() -> { // reciever primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class, NullRestrictedValue.class)). + invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + + } + + + static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { + // Get + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.get(); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.get(); + }); + // Incorrect arity + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.get(Void.class); + }); + + + // Set + // Incorrect argument types + checkCCE(() -> { // value reference class + vh.set(Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.set(); + }); + checkWMTE(() -> { // > + vh.set(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetVolatile + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getVolatile(); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getVolatile(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(Void.class); + }); + + + // SetVolatile + // Incorrect argument types + checkCCE(() -> { // value reference class + vh.setVolatile(Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setVolatile(); + }); + checkWMTE(() -> { // > + vh.setVolatile(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetOpaque + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getOpaque(); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getOpaque(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(Void.class); + }); + + + // SetOpaque + // Incorrect argument types + checkCCE(() -> { // value reference class + vh.setOpaque(Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setOpaque(); + }); + checkWMTE(() -> { // > + vh.setOpaque(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAcquire + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getAcquire(); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(Void.class); + }); + + + // SetRelease + // Incorrect argument types + checkCCE(() -> { // value reference class + vh.setRelease(Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setRelease(); + }); + checkWMTE(() -> { // > + vh.setRelease(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndSet + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.compareAndSet(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.compareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSet + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetPlain(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetPlain(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetVolatile + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSet(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSet(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSet(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetAcquire + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetAcquire(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetAcquire(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetRelease + // Incorrect argument types + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetRelease(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchange + // Incorrect argument types + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeAcquire + // Incorrect argument types + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeRelease + // Incorrect argument types + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSet + // Incorrect argument types + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSet(NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSet(NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSetAcquire + // Incorrect argument types + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSetRelease + // Incorrect argument types + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + } + + static void testStaticFieldWrongMethodType(Handles hs) throws Throwable { + int i = 0; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) { + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void x = (Void) hs.get(am, methodType(Void.class)). + invokeExact(); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class)). + invokeExact(); + }); + // Incorrect arity + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(Class.class)). + invokeExact(Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + hs.checkWMTEOrCCE(() -> { // value reference class + hs.get(am, methodType(void.class, Class.class)). + invokeExact(Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + hs.get(am, methodType(void.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + hs.get(am, methodType(void.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + // Incorrect argument types + hs.checkWMTEOrCCE(() -> { // expected reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, Class.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = (boolean) hs.get(am, methodType(boolean.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + // Incorrect argument types + hs.checkWMTEOrCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, NullRestrictedValue.class)). + invokeExact(Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + // Incorrect argument types + hs.checkWMTEOrCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class)). + invokeExact(Void.class); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, NullRestrictedValue.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + + } + + + static void testArrayWrongMethodType(VarHandle vh) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + Arrays.fill(array, NullRestrictedValue.of((byte)20,(short)1854)); + + // Get + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.get(null, 0); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.get(Void.class, 0); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.get(0, 0); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.get(array, 0); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.get(array, 0); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.get(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.get(array, 0, Void.class); + }); + + + // Set + // Incorrect argument types + checkNPE(() -> { // null array + vh.set(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + vh.set(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.set(array, 0, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.set(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + vh.set(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.set(); + }); + checkWMTE(() -> { // > + vh.set(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetVolatile + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(null, 0); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(Void.class, 0); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(0, 0); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(array, Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getVolatile(array, 0); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getVolatile(array, 0); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getVolatile(array, 0, Void.class); + }); + + + // SetVolatile + // Incorrect argument types + checkNPE(() -> { // null array + vh.setVolatile(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + vh.setVolatile(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setVolatile(array, 0, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setVolatile(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + vh.setVolatile(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setVolatile(); + }); + checkWMTE(() -> { // > + vh.setVolatile(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetOpaque + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(null, 0); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(Void.class, 0); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(0, 0); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(array, Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getOpaque(array, 0); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getOpaque(array, 0); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getOpaque(array, 0, Void.class); + }); + + + // SetOpaque + // Incorrect argument types + checkNPE(() -> { // null array + vh.setOpaque(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + vh.setOpaque(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setOpaque(array, 0, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setOpaque(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + vh.setOpaque(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setOpaque(); + }); + checkWMTE(() -> { // > + vh.setOpaque(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAcquire + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(null, 0); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(Void.class, 0); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(0, 0); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(array, Void.class); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void x = (Void) vh.getAcquire(array, 0); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAcquire(array, 0); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(array, 0, Void.class); + }); + + + // SetRelease + // Incorrect argument types + checkNPE(() -> { // null array + vh.setRelease(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + vh.setRelease(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + vh.setRelease(array, 0, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + vh.setRelease(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + vh.setRelease(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + vh.setRelease(); + }); + checkWMTE(() -> { // > + vh.setRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndSet + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.compareAndSet(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.compareAndSet(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.compareAndSet(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.compareAndSet(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.compareAndSet(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.compareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSet + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetPlain(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetPlain(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetPlain(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetPlain(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetPlain(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetVolatile + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSet(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSet(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSet(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSet(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSet(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetAcquire(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetAcquire(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetAcquire(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetAcquire(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetAcquire(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // WeakCompareAndSetRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = vh.weakCompareAndSetRelease(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + boolean r = vh.weakCompareAndSetRelease(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = vh.weakCompareAndSetRelease(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = vh.weakCompareAndSetRelease(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = vh.weakCompareAndSetRelease(); + }); + checkWMTE(() -> { // > + boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchange + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeAcquire + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // CompareAndExchangeRelease + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSet + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, Void.class); + }); + checkWMTE(() -> { // reciarrayever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSetAcquire + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, Void.class); + }); + checkWMTE(() -> { // reciarrayever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + // GetAndSetRelease + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, Void.class); + }); + checkWMTE(() -> { // reciarrayever primitive class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + checkCCE(() -> { // reference class + Void r = (Void) vh.getAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) vh.getAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + + + } + + static void testArrayWrongMethodType(Handles hs) throws Throwable { + NullRestrictedValue[] array = (NullRestrictedValue[]) ValueClass.newNullRestrictedAtomicArray(NullRestrictedValue.class, 10, NullRestrictedValue.of((byte)20,(short)1854)); + Arrays.fill(array, NullRestrictedValue.of((byte)20,(short)1854)); + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) { + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class)). + invokeExact((NullRestrictedValue[]) null, 0); + }); + hs.checkWMTEOrCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, int.class)). + invokeExact(Void.class, 0); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class, int.class)). + invokeExact(0, 0); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, Class.class)). + invokeExact(array, Void.class); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void x = (Void) hs.get(am, methodType(Void.class, NullRestrictedValue[].class, int.class)). + invokeExact(array, 0); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class)). + invokeExact(array, 0); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, Class.class)). + invokeExact(array, 0, Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + // Incorrect argument types + checkNPE(() -> { // null array + hs.get(am, methodType(void.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class)). + invokeExact((NullRestrictedValue[]) null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // array reference class + hs.get(am, methodType(void.class, Class.class, int.class, NullRestrictedValue.class)). + invokeExact(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // value reference class + hs.get(am, methodType(void.class, NullRestrictedValue[].class, int.class, Class.class)). + invokeExact(array, 0, Void.class); + }); + checkWMTE(() -> { // receiver primitive class + hs.get(am, methodType(void.class, int.class, int.class, NullRestrictedValue.class)). + invokeExact(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + hs.get(am, methodType(void.class, NullRestrictedValue[].class, Class.class, NullRestrictedValue.class)). + invokeExact(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + hs.get(am, methodType(void.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + hs.get(am, methodType(void.class, NullRestrictedValue[].class, int.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + // Incorrect argument types + checkNPE(() -> { // null receiver + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((NullRestrictedValue[]) null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // receiver reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, Class.class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // expected reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, Class.class, NullRestrictedValue.class)). + invokeExact(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // receiver primitive class + boolean r = (boolean) hs.get(am, methodType(boolean.class, int.class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, Class.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + boolean r = (boolean) hs.get(am, methodType(boolean.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + boolean r = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + // Incorrect argument types + checkNPE(() -> { // null receiver + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact((NullRestrictedValue[]) null, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // expected reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, Class.class, NullRestrictedValue.class)). + invokeExact(array, 0, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // actual reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(0, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, Class.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, NullRestrictedValue.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + // Incorrect argument types + checkNPE(() -> { // null array + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class)). + invokeExact((NullRestrictedValue[]) null, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // array reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, Class.class, int.class, NullRestrictedValue.class)). + invokeExact(Void.class, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + hs.checkWMTEOrCCE(() -> { // value reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, Class.class)). + invokeExact(array, 0, Void.class); + }); + checkWMTE(() -> { // array primitive class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class, int.class, NullRestrictedValue.class)). + invokeExact(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // index reference class + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, Class.class, NullRestrictedValue.class)). + invokeExact(array, Void.class, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect return type + hs.checkWMTEOrCCE(() -> { // reference class + Void r = (Void) hs.get(am, methodType(Void.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + checkWMTE(() -> { // primitive class + boolean x = (boolean) hs.get(am, methodType(boolean.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854)); + }); + // Incorrect arity + checkWMTE(() -> { // 0 + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class)). + invokeExact(); + }); + checkWMTE(() -> { // > + NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, NullRestrictedValue[].class, int.class, NullRestrictedValue.class, Class.class)). + invokeExact(array, 0, NullRestrictedValue.of((byte)20,(short)1854), Void.class); + }); + } + + + } +} diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java index 84c68b6e71c2..2bd3fafbfd99 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { static short static_v = (short)0x0123; - final short final_v = (short)0x0123; + final short final_v; - short v = (short)0x0123; + short v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeShort extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeShort() { + final_v = (short)0x0123; + v = (short)0x0123; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java index c5937eda15d9..49a601f38d4c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,9 +51,9 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { static String static_v = "foo"; - final String final_v = "foo"; + final String final_v; - String v = "foo"; + String v; VarHandle vhFinalField; @@ -65,6 +65,12 @@ public class VarHandleTestMethodTypeString extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeString() { + final_v = "foo"; + v = "foo"; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java index 9f7c5025cef3..17cdcb7417f5 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ * @bug 8156486 * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value * @run junit/othervm VarHandleTestMethodTypeValue * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodTypeValue * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestMethodTypeValue @@ -53,9 +54,9 @@ public class VarHandleTestMethodTypeValue extends VarHandleBaseTest { static Value static_v = Value.getInstance(10); - final Value final_v = Value.getInstance(10); + final Value final_v; - Value v = Value.getInstance(10); + Value v; VarHandle vhFinalField; @@ -67,6 +68,12 @@ public class VarHandleTestMethodTypeValue extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodTypeValue() { + final_v = Value.getInstance(10); + v = Value.getInstance(10); + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template index df85af59d46c..54357cc61f20 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #if[Value] * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value #end[Value] * @run junit/othervm -Diters=10 -Xint VarHandleTestAccess$Type$ * @@ -45,6 +46,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +#if[NullRestricted] +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +#end[NullRestricted] import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -54,21 +60,21 @@ import org.junit.jupiter.params.provider.MethodSource; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { - static final $type$ static_final_v = $value1$; + static final {#if[NullRestricted]?@NullRestricted }$type$ static_final_v = $value1$; - static $type$ static_v; + static {#if[NullRestricted]?@NullRestricted }$type$ static_v = $value1$; - final $type$ final_v = $value1$; + final {#if[NullRestricted]?@NullRestricted }$type$ final_v; - $type$ v; + {#if[NullRestricted]?@NullRestricted }$type$ v; - static final $type$ static_final_v2 = $value1$; + static final {#if[NullRestricted]?@NullRestricted }$type$ static_final_v2 = $value1$; - static $type$ static_v2; + static {#if[NullRestricted]?@NullRestricted }$type$ static_v2 = $value1$; - final $type$ final_v2 = $value1$; + final {#if[NullRestricted]?@NullRestricted }$type$ final_v2; - $type$ v2; + {#if[NullRestricted]?@NullRestricted }$type$ v2; VarHandle vhFinalField; @@ -82,7 +88,15 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { #if[Object] VarHandle vhArrayObject; + #end[Object] + public VarHandleTestAccess$Type$() { + final_v = $value1$; + v = $value1$; + final_v2 = $value1$; + v2 = $value1$; + super(); + } VarHandle[] allocate(boolean same) { List vhs = new ArrayList<>(); @@ -308,12 +322,22 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { cases.add(new VarHandleAccessTestCase("Instance field unsupported", vhField, vh -> testInstanceFieldUnsupported(this, vh), false)); +#if[NullRestricted] + cases.add(new VarHandleAccessTestCase("Instance field null pointer exception", + vhField, vh -> testInstanceFieldNullPointerException(this, vh), + false)); +#end[NullRestricted] cases.add(new VarHandleAccessTestCase("Static field", vhStaticField, VarHandleTestAccess$Type$::testStaticField)); cases.add(new VarHandleAccessTestCase("Static field unsupported", vhStaticField, VarHandleTestAccess$Type$::testStaticFieldUnsupported, false)); +#if[NullRestricted] + cases.add(new VarHandleAccessTestCase("Static field null pointer exception", + vhStaticField, VarHandleTestAccess$Type$::testStaticFieldNullPointerException, + false)); +#end[NullRestricted] cases.add(new VarHandleAccessTestCase("Array", vhArray, VarHandleTestAccess$Type$::testArray)); @@ -332,6 +356,11 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vhArrayObject, VarHandleTestAccess$Type$::testArrayStoreException, false)); #end[Object] +#if[NullRestricted] + cases.add(new VarHandleAccessTestCase("Array null pointer exception", + vhArrayObject, VarHandleTestAccess$Type$::testArrayNullPointerException, + false)); +#end[NullRestricted] // Work around issue with jtreg summary reporting which truncates // the String result of Object.toString to 30 characters, hence // the first dummy argument @@ -1455,7 +1484,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { static void testArray(VarHandle vh) { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; for (int i = 0; i < array.length; i++) { // Plain @@ -1767,7 +1796,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } static void testArrayUnsupported(VarHandle vh) { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; int i = 0; #if[!CAS] @@ -1870,7 +1899,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { } static void testArrayIndexOutOfBounds(VarHandle vh) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) { final int ci = i; @@ -2006,10 +2035,10 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { #end[Bitwise] } } - #if[Object] + static void testArrayStoreException(VarHandle vh) throws Throwable { - Object[] array = new $type$[10]; + Object[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; Arrays.fill(array, $value1$); Object value = new Object(); @@ -2089,5 +2118,245 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); } #end[Object] +#if[NullRestricted] + + static void testInstanceFieldNullPointerException(VarHandleTestAccess$Type$ recv, VarHandle vh) throws Throwable { + $type$ value = null; + + // Set + checkNPE(() -> { + vh.set(recv, value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(recv, value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(recv, value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(recv, value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet(recv, $value1$, value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(recv, $value1$, value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(recv, $value1$, value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(recv, $value1$, value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchange(recv, $value1$, value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeAcquire(recv, $value1$, value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeRelease(recv, $value1$, value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSet(recv, value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetAcquire(recv, value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetRelease(recv, value); + }); + } + + static void testStaticFieldNullPointerException(VarHandle vh) throws Throwable { + $type$ value = null; + + // Set + checkNPE(() -> { + vh.set(value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet($value1$, value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain($value1$, value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet($value1$, value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire($value1$, value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease($value1$, value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchange($value1$, value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeAcquire($value1$, value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeRelease($value1$, value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSet(value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetAcquire(value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetRelease(value); + }); + } + + static void testArrayNullPointerException(VarHandle vh) throws Throwable { + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; + $type$ value = null; + + // Set + checkNPE(() -> { + vh.set(array, 0, value); + }); + + // SetVolatile + checkNPE(() -> { + vh.setVolatile(array, 0, value); + }); + + // SetOpaque + checkNPE(() -> { + vh.setOpaque(array, 0, value); + }); + + // SetRelease + checkNPE(() -> { + vh.setRelease(array, 0, value); + }); + + // CompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.compareAndSet(array, 0, $value1$, value); + }); + + // WeakCompareAndSet + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetPlain(array, 0, $value1$, value); + }); + + // WeakCompareAndSetVolatile + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSet(array, 0, $value1$, value); + }); + + // WeakCompareAndSetAcquire + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetAcquire(array, 0, $value1$, value); + }); + + // WeakCompareAndSetRelease + checkNPE(() -> { // receiver reference class + boolean r = vh.weakCompareAndSetRelease(array, 0, $value1$, value); + }); + + // CompareAndExchange + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchange(array, 0, $value1$, value); + }); + + // CompareAndExchangeAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeAcquire(array, 0, $value1$, value); + }); + + // CompareAndExchangeRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.compareAndExchangeRelease(array, 0, $value1$, value); + }); + + // GetAndSet + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSet(array, 0, value); + }); + + // GetAndSetAcquire + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetAcquire(array, 0, value); + }); + + // GetAndSetRelease + checkNPE(() -> { // receiver reference class + $type$ x = ($type$) vh.getAndSetRelease(array, 0, value); + }); + } +#end[NullRestricted] } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template index 076befb5685b..dff8b0306042 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #if[Value] * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value #end[Value] * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations * to hit compilation thresholds @@ -40,6 +41,11 @@ import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; +#if[NullRestricted] +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +#end[NullRestricted] import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; @@ -48,13 +54,13 @@ import org.junit.jupiter.params.provider.MethodSource; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { - static final $type$ static_final_v = $value1$; + static final {#if[NullRestricted]?@NullRestricted }$type$ static_final_v = $value1$; - static $type$ static_v; + static {#if[NullRestricted]?@NullRestricted }$type$ static_v = $value1$; - final $type$ final_v = $value1$; + final {#if[NullRestricted]?@NullRestricted }$type$ final_v; - $type$ v; + {#if[NullRestricted]?@NullRestricted }$type$ v; VarHandle vhFinalField; @@ -66,6 +72,12 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodHandleAccess$Type$() { + final_v = $value1$; + v = $value1$; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( @@ -92,12 +104,22 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { cases.add(new MethodHandleAccessTestCase("Instance field unsupported", vhField, f, hs -> testInstanceFieldUnsupported(this, hs), false)); +#if[NullRestricted] + cases.add(new MethodHandleAccessTestCase("Instance field null pointer exception", + vhField, f, hs -> testInstanceFieldNullPointerException(this, hs), + false)); +#end[NullRestricted] cases.add(new MethodHandleAccessTestCase("Static field", vhStaticField, f, VarHandleTestMethodHandleAccess$Type$::testStaticField)); cases.add(new MethodHandleAccessTestCase("Static field unsupported", vhStaticField, f, VarHandleTestMethodHandleAccess$Type$::testStaticFieldUnsupported, false)); +#if[NullRestricted] + cases.add(new MethodHandleAccessTestCase("Static field null pointer exception", + vhStaticField, f, VarHandleTestMethodHandleAccess$Type$::testStaticFieldNullPointerException, + false)); +#end[NullRestricted] cases.add(new MethodHandleAccessTestCase("Array", vhArray, f, VarHandleTestMethodHandleAccess$Type$::testArray)); @@ -107,6 +129,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { cases.add(new MethodHandleAccessTestCase("Array index out of bounds", vhArray, f, VarHandleTestMethodHandleAccess$Type$::testArrayIndexOutOfBounds, false)); +#if[NullRestricted] + cases.add(new MethodHandleAccessTestCase("Array null pointer exception", + vhArray, f, VarHandleTestMethodHandleAccess$Type$::testArrayNullPointerException, + false)); +#end[NullRestricted] } // Work around issue with jtreg summary reporting which truncates @@ -811,7 +838,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { static void testArray(Handles hs) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; for (int i = 0; i < array.length; i++) { // Plain @@ -1127,7 +1154,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } static void testArrayUnsupported(Handles hs) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; final int i = 0; #if[!CAS] @@ -1168,7 +1195,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } static void testArrayIndexOutOfBounds(Handles hs) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; for (int i : new int[]{-1, Integer.MIN_VALUE, 10, 11, Integer.MAX_VALUE}) { final int ci = i; @@ -1222,5 +1249,99 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { #end[Bitwise] } } +#if[NullRestricted] + + static void testInstanceFieldNullPointerException(VarHandleTestMethodHandleAccess$Type$ recv, Handles hs) throws Throwable { + $type$ value = null; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(recv, value); + }); + } +#if[CAS] + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(recv, $value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact(recv, $value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact(recv, value); + }); + } +#end[CAS] + } + + static void testStaticFieldNullPointerException(Handles hs) throws Throwable { + $type$ value = null; + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(value); + }); + } +#if[CAS] + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact($value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact($value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact(value); + }); + } +#end[CAS] + } + + static void testArrayNullPointerException(Handles hs) throws Throwable { + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; + $type$ value = null; + + final int i = 0; + for (TestAccessMode am : testAccessModesOfType(TestAccessType.SET)) { + checkNPE(am, () -> { + hs.get(am).invokeExact(array, i, value); + }); + } +#if[CAS] + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_SET)) { + checkNPE(am, () -> { + boolean r = (boolean) hs.get(am).invokeExact(array, i, $value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.COMPARE_AND_EXCHANGE)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact(array, i, $value1$, value); + }); + } + + for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET_AND_SET)) { + checkNPE(am, () -> { + $type$ r = ($type$) hs.get(am).invokeExact(array, i, value); + }); + } +#end[CAS] + } +#end[NullRestricted] } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template index e1717283115f..f44b17b2d879 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #if[Value] * @enablePreview * @modules java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.value #end[Value] * @run junit/othervm VarHandleTestMethodType$Type$ * @run junit/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestMethodType$Type$ @@ -44,6 +45,11 @@ import java.util.List; import static java.lang.invoke.MethodType.*; +#if[NullRestricted] +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +#end[NullRestricted] import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; @@ -51,13 +57,13 @@ import org.junit.jupiter.params.provider.MethodSource; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { - static final $type$ static_final_v = $value1$; + static final {#if[NullRestricted]?@NullRestricted }$type$ static_final_v = $value1$; - static $type$ static_v = $value1$; + static {#if[NullRestricted]?@NullRestricted }$type$ static_v = $value1$; - final $type$ final_v = $value1$; + final {#if[NullRestricted]?@NullRestricted }$type$ final_v; - $type$ v = $value1$; + {#if[NullRestricted]?@NullRestricted }$type$ v; VarHandle vhFinalField; @@ -69,6 +75,12 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { VarHandle vhArray; + public VarHandleTestMethodType$Type$() { + final_v = $value1$; + v = $value1$; + super(); + } + @BeforeAll public void setup() throws Exception { vhFinalField = MethodHandles.lookup().findVarHandle( @@ -2026,7 +2038,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { static void testArrayWrongMethodType(VarHandle vh) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; Arrays.fill(array, $value1$); // Get @@ -3006,7 +3018,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { } static void testArrayWrongMethodType(Handles hs) throws Throwable { - $type$[] array = new $type$[10]; + $type$[] array = {#if[NullRestricted]?($type$[]) ValueClass.newNullRestrictedAtomicArray($type$.class, 10, $value1$):new $type$[10]}; Arrays.fill(array, $value1$); for (TestAccessMode am : testAccessModesOfType(TestAccessType.GET)) { diff --git a/test/jdk/java/lang/invoke/VarHandles/generate-vh-tests.sh b/test/jdk/java/lang/invoke/VarHandles/generate-vh-tests.sh index 1d860551aa8b..bbed2bcaf83c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/generate-vh-tests.sh +++ b/test/jdk/java/lang/invoke/VarHandles/generate-vh-tests.sh @@ -9,7 +9,7 @@ SPP=build.tools.spp.Spp # desirable to generate code using ASM which will allow more flexibility # in the kinds of tests that are generated. -for type in boolean byte short char int long float double String Value +for type in boolean byte short char int long float double String Value NullRestrictedValue do Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" args="-K$type -Dtype=$type -DType=$Type" @@ -37,6 +37,9 @@ do Value) args="$args -KObject -KValue" ;; + NullRestrictedValue) + args="$args -KObject -KValue -KNullRestricted" + ;; esac wrong_primitive_type=boolean @@ -93,6 +96,10 @@ do value2="Value.getInstance(20)" value3="Value.getInstance(30)" ;; + NullRestrictedValue) + value1="NullRestrictedValue.of((byte)20,(short)1854)" + value2="NullRestrictedValue.of((byte)-42,(short)1854)" + value3="NullRestrictedValue.of((byte)20,(short)-31083)" esac args="$args -Dvalue1=$value1 -Dvalue2=$value2 -Dvalue3=$value3 -Dwrong_primitive_type=$wrong_primitive_type" From 689b4a64153056458dccf1529585c8665ea13132 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Tue, 1 Sep 2026 23:30:23 +0000 Subject: [PATCH 183/223] 8390689: TestHeapDumpForInvokeDynamic fails HPROF verification when LingeredApp runs on a virtual thread Reviewed-by: cjplummer, ysuenaga --- .../hotspot/oops/InstanceStackChunkKlass.java | 31 ++++++++++++++++++- test/hotspot/jtreg/ProblemList-Virtual.txt | 1 - 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceStackChunkKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceStackChunkKlass.java index 246208582c12..75344728e814 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceStackChunkKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceStackChunkKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,4 +51,33 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc public InstanceStackChunkKlass(Address addr) { super(addr); } + + @Override + public long getObjectSize(Oop object) { + // Mirrors InstanceStackChunkKlass::oop_size in the VM, in bytes. + long stackSizeInWords = ((IntField) findField("size", "I")).getValue(object); + return instanceSize(stackSizeInWords); + } + + private long instanceSize(long stackSizeInWords) { + long sizeInWords = getSizeHelper() + stackSizeInWords + gcDataSize(stackSizeInWords); + return Oop.alignObjectSize(sizeInWords * VM.getVM().getAddressSize()); + } + + private static long gcDataSize(long stackSizeInWords) { + return bitmapSize(stackSizeInWords); + } + + private static long bitmapSize(long stackSizeInWords) { + long bitsPerWord = VM.getVM().getBytesPerWord() * 8L; + return bitmapSizeInBits(stackSizeInWords) / bitsPerWord; + } + + private static long bitmapSizeInBits(long stackSizeInWords) { + VM vm = VM.getVM(); + // Need one bit per potential narrowOop* or oop* address. + long bitsPerWord = vm.getBytesPerWord() * 8L; + long sizeInBits = stackSizeInWords * (vm.getBytesPerWord() / vm.getHeapOopSize()); + return vm.alignUp(sizeInBits, bitsPerWord); + } } diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 4a6349555114..53bb850a6ecc 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -27,7 +27,6 @@ runtime/jni/critical/SuspendInCritical.java 8384369 generic-all serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java 8308026 generic-all serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java 8264699 generic-all -serviceability/sa/TestHeapDumpForInvokeDynamic.java 8390689 generic-all vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all vmTestbase/nsk/jvmti/unit/functions/Dispose/JvmtiTest/TestDescription.java 8387429 generic-all From 71638cedfa79c96a3e78607701516f300723b4b6 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 2 Sep 2026 00:14:35 +0000 Subject: [PATCH 184/223] 8391311: GenShen: Avoid double region iteration in final mark Reviewed-by: wkemper, shade --- .../gc/shenandoah/shenandoahGeneration.cpp | 19 +++++-------- .../shenandoahHeapRegionClosures.cpp | 28 +++++++++++-------- .../shenandoahHeapRegionClosures.hpp | 7 +++-- .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 +- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 139406246693..0068a8574ee7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,17 +258,12 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_update_region_states : ShenandoahPhaseTimings::degen_gc_final_update_region_states); - ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context()); - parallel_heap_region_iterate(&cl); - - if (is_young()) { - // We always need to update the watermark for old regions. If there - // are mixed collections pending, we also need to synchronize the - // pinned status for old regions. Since we are already visiting every - // old region here, go ahead and sync the pin status too. - ShenandoahFinalMarkUpdateRegionStateClosure old_cl(nullptr); - heap->old_generation()->parallel_heap_region_iterate(&old_cl); - } + // Update region state for every active region, but only update the liveness data for + // the generation we marked. We always need to update the watermark for old regions. + // If there are mixed collections pending, we also need to synchronize the pinned status + // for old regions. + ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context(), this); + heap->global_generation()->parallel_heap_region_iterate(&cl); } // Tally the census counts and compute the adaptive tenuring threshold diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp index 6af7548c39ba..bb373a2d97d5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp @@ -1,6 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ * */ +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" @@ -54,21 +55,24 @@ void ShenandoahSynchronizePinnedRegionStates::synchronize_pin_count(ShenandoahHe } } -ShenandoahFinalMarkUpdateRegionStateClosure::ShenandoahFinalMarkUpdateRegionStateClosure(ShenandoahMarkingContext *ctx) : - _ctx(ctx) { } +ShenandoahFinalMarkUpdateRegionStateClosure::ShenandoahFinalMarkUpdateRegionStateClosure(ShenandoahMarkingContext* ctx, ShenandoahGeneration* generation) : + _ctx(ctx), _generation(generation) { + assert(_ctx != nullptr, "Marking context is required"); + assert(_generation != nullptr, "Generation is required"); +} void ShenandoahFinalMarkUpdateRegionStateClosure::heap_region_do(ShenandoahHeapRegion* r) { + // Region data can only be adjusted for regions in the generation this cycle marked. + // For old regions during a young cycle, we only sync the pin status and update + // the watermark. We cannot reset the TAMS for old regions because we rely on + // that to keep promoted objects alive after old marking is complete. + const bool in_marked_generation = _generation->contains(r); if (r->is_active()) { - if (_ctx != nullptr) { - // _ctx may be null when this closure is used to sync only the pin status - // update the watermark of old regions. For old regions we cannot reset - // the TAMS because we rely on that to keep promoted objects alive after - // old marking is complete. - + if (in_marked_generation) { // All allocations past TAMS are implicitly live, adjust the region data. // Bitmaps/TAMS are swapped at this point, so we need to poll complete bitmap. - HeapWord *tams = _ctx->top_at_mark_start(r); - HeapWord *top = r->top(); + HeapWord* tams = _ctx->top_at_mark_start(r); + HeapWord* top = r->top(); if (top > tams) { r->increase_live_data_alloc_words(pointer_delta(top, tams)); } @@ -89,7 +93,7 @@ void ShenandoahFinalMarkUpdateRegionStateClosure::heap_region_do(ShenandoahHeapR } } else { assert(!r->has_live(), "Region %zu should have no live data", r->index()); - assert(_ctx == nullptr || _ctx->top_at_mark_start(r) == r->top(), + assert(!in_marked_generation || _ctx->top_at_mark_start(r) == r->top(), "Region %zu should have correct TAMS", r->index()); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp index 2777b49fafff..a1b348ca7644 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp @@ -94,14 +94,17 @@ class ShenandoahSynchronizePinnedRegionStates : public ShenandoahHeapRegionClosu }; class ShenandoahMarkingContext; +class ShenandoahGeneration; -// Synchronizes region pinned status, sets update watermark and adjust live data tally for regions +// Synchronizes region pinned status, sets update watermark and adjusts live data tally for regions. +// Live data tally is only adjusted for regions in the given generation. class ShenandoahFinalMarkUpdateRegionStateClosure : public ShenandoahHeapRegionClosure { private: ShenandoahMarkingContext* const _ctx; + ShenandoahGeneration* const _generation; ShenandoahSynchronizePinnedRegionStates _pins; public: - explicit ShenandoahFinalMarkUpdateRegionStateClosure(ShenandoahMarkingContext* ctx); + explicit ShenandoahFinalMarkUpdateRegionStateClosure(ShenandoahMarkingContext* ctx, ShenandoahGeneration* generation); void heap_region_do(ShenandoahHeapRegion* r) override; bool is_thread_safe() override { return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 26e61d31fa81..020c66aa1fe6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -452,7 +452,7 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_update_region_states : ShenandoahPhaseTimings::degen_gc_final_update_region_states); - ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context()); + ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context(), this); parallel_heap_region_iterate(&cl); heap->assert_pinned_region_status(this); From d4f6586086728909b18f3ce13271ce39e0c98e49 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 2 Sep 2026 00:17:18 +0000 Subject: [PATCH 185/223] 8390604: Speed up native --> Java transitions Co-authored-by: Martin Doerr Co-authored-by: Amit Kumar Co-authored-by: Fei Yang Reviewed-by: pchilanomate, dholmes --- .../cpu/aarch64/downcallLinker_aarch64.cpp | 13 ++++----- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 14 ++++----- .../templateInterpreterGenerator_aarch64.cpp | 9 ++---- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 12 ++++---- .../arm/templateInterpreterGenerator_arm.cpp | 13 ++++----- src/hotspot/cpu/ppc/downcallLinker_ppc.cpp | 9 ++---- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 20 ++----------- .../ppc/templateInterpreterGenerator_ppc.cpp | 17 ++--------- .../cpu/riscv/downcallLinker_riscv.cpp | 15 ++++------ src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 15 ++++------ .../templateInterpreterGenerator_riscv.cpp | 15 ++-------- src/hotspot/cpu/s390/downcallLinker_s390.cpp | 8 ++--- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 24 +++++---------- .../templateInterpreterGenerator_s390.cpp | 17 ++++------- src/hotspot/cpu/x86/downcallLinker_x86_64.cpp | 8 ++--- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 8 ++--- .../x86/templateInterpreterGenerator_x86.cpp | 8 ++--- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 7 ++--- .../share/runtime/interfaceSupport.inline.hpp | 4 ++- src/hotspot/share/runtime/javaThread.cpp | 29 ++++++------------- src/hotspot/share/runtime/javaThread.hpp | 3 -- .../share/runtime/javaThread.inline.hpp | 14 ++------- src/hotspot/share/runtime/sharedRuntime.cpp | 21 ++++++++++++++ src/hotspot/share/runtime/sharedRuntime.hpp | 4 +++ 24 files changed, 109 insertions(+), 198 deletions(-) diff --git a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp index 47c55976a4f3..766b2b4dda0a 100644 --- a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp @@ -308,8 +308,10 @@ void DowncallLinker::StubGenerator::generate() { // Restore cpu control state after JNI call __ restore_cpu_control_state_after_jni(rscratch1, tmp1); - __ mov(tmp1, _thread_in_vm); - __ strw(tmp1, Address(rthread, JavaThread::thread_state_offset())); + // change thread state + __ mov(tmp1, _thread_in_Java); + __ lea(tmp2, Address(rthread, JavaThread::thread_state_offset())); + __ stlrw(tmp1, tmp2); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -326,11 +328,6 @@ void DowncallLinker::StubGenerator::generate() { __ bind(L_after_safepoint_poll); - // change thread state - __ mov(tmp1, _thread_in_Java); - __ lea(tmp2, Address(rthread, JavaThread::thread_state_offset())); - __ stlrw(tmp1, tmp2); - __ block_comment("reguard stack check"); __ ldrb(tmp1, Address(rthread, JavaThread::stack_guard_state_offset())); __ cmpw(tmp1, StackOverflow::stack_guard_yellow_reserved_disabled); @@ -356,7 +353,7 @@ void DowncallLinker::StubGenerator::generate() { __ mov(c_rarg0, rthread); assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); - __ lea(tmp1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + __ lea(tmp1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans))); __ blr(tmp1); if (should_save_return_value) { diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 9cee41626a51..e2b8e1a1ed94 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -2047,9 +2047,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label safepoint_in_progress, safepoint_in_progress_done; - __ mov(rscratch1, _thread_in_vm); - - __ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset())); + // change thread state + __ mov(rscratch1, _thread_in_Java); + __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); + __ stlrw(rscratch1, rscratch2); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -2067,11 +2068,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ bind(safepoint_in_progress_done); } - // change thread state - __ mov(rscratch1, _thread_in_Java); - __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); - __ stlrw(rscratch1, rscratch2); - if (method->is_object_wait0()) { // Check preemption for Object.wait() __ ldr(rscratch1, Address(rthread, JavaThread::preempt_alternate_return_offset())); @@ -2273,7 +2269,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, #ifndef PRODUCT assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); #endif - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans))); __ blr(rscratch1); // Restore any method result value diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 9c53800dd34b..c317629d6cc9 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1422,7 +1422,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ verify_sve_vector_length(); // change thread state - __ mov(rscratch1, _thread_in_vm); + __ mov(rscratch1, _thread_in_Java); __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); @@ -1447,18 +1447,13 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // hand. // __ mov(c_rarg0, rthread); - __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans))); __ blr(rscratch2); __ get_method(rmethod); __ reinit_heapbase(); __ bind(Continue); } - // change thread state - __ mov(rscratch1, _thread_in_Java); - __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); - __ stlrw(rscratch1, rscratch2); - // Check preemption for Object.wait() Label not_preempted; __ ldr(rscratch1, Address(rthread, JavaThread::preempt_alternate_return_offset())); diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index fb24be65294b..5779bcc26ac6 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1263,9 +1263,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ c2bool(R0); } - // Do a safepoint check + // Perform thread state transition Label call_safepoint_runtime, return_to_java; - __ mov(Rtemp, _thread_in_vm); + __ mov(Rtemp, _thread_in_Java); __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); // make sure the store is observed before reading the SafepointSynchronize state and further mem refs @@ -1273,6 +1273,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad | MacroAssembler::StoreStore), Rtemp); } + // Do a safepoint check __ safepoint_poll(R2, call_safepoint_runtime); __ ldr_u32(R3, Address(Rthread, JavaThread::suspend_flags_offset())); __ cmp(R3, 0); @@ -1280,12 +1281,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ bind(return_to_java); - // Perform thread state transition and reguard stack yellow pages if needed + // Reguard stack yellow pages if needed Label reguard, reguard_done; - __ mov(Rtemp, _thread_in_Java); __ ldr_s32(R2, Address(Rthread, JavaThread::stack_guard_state_offset())); - __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); - __ cmp(R2, StackOverflow::stack_guard_yellow_reserved_disabled); __ b(reguard, eq); __ bind(reguard_done); @@ -1336,7 +1334,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ bind(call_safepoint_runtime); push_result_registers(masm, ret_type); __ mov(R0, Rthread); - __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); pop_result_registers(masm, ret_type); __ b(return_to_java); diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index 99f30a8f2669..b7e055b317b9 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1013,8 +1013,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ restore_default_fp_mode(); } - // Do safepoint check - __ mov(Rtemp, _thread_in_vm); + // Perform Native->Java thread transition + __ mov(Rtemp, _thread_in_Java); __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); // Force this write out before the read below @@ -1033,6 +1033,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { saved_result_fp = fnoreg; #endif // __ABI_HARD__ + // Do safepoint check { Label call, skip_call; __ safepoint_poll(Rtemp, call); @@ -1041,7 +1042,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ b(skip_call, eq); __ bind(call); __ mov(R0, Rthread); - __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), relocInfo::none); + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans), relocInfo::none); __ bind(skip_call); #if R9_IS_SCRATCHED @@ -1049,10 +1050,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { #endif } - // Perform Native->Java thread transition - __ mov(Rtemp, _thread_in_Java); - __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); - // Zero handles and last_java_sp __ reset_last_Java_frame(Rtemp); __ ldr(R3, Address(Rthread, JavaThread::active_handles_offset())); diff --git a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp index e9ca213c72c9..909d1e585825 100644 --- a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp @@ -297,7 +297,7 @@ void DowncallLinker::StubGenerator::generate() { Label L_after_reguard; if (_needs_transition) { - __ li(tmp, _thread_in_vm); + __ li(tmp, _thread_in_Java); __ release(); __ stw(tmp, in_bytes(JavaThread::thread_state_offset()), R16_thread); if (!UseSystemMemoryBarrier) { @@ -311,11 +311,6 @@ void DowncallLinker::StubGenerator::generate() { __ bne(CR0, L_safepoint_poll_slow_path); __ bind(L_after_safepoint_poll); - // change thread state - __ li(tmp, _thread_in_Java); - __ lwsync(); // Acquire safepoint and suspend state, release thread state. - __ stw(tmp, in_bytes(JavaThread::thread_state_offset()), R16_thread); - __ block_comment("reguard stack check"); __ lwz(tmp, in_bytes(JavaThread::stack_guard_state_offset()), R16_thread); __ cmpwi(CR0, tmp, StackOverflow::stack_guard_yellow_reserved_disabled); @@ -340,7 +335,7 @@ void DowncallLinker::StubGenerator::generate() { out_reg_spiller.generate_spill(_masm, out_spill_offset); } - __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, JavaThread::check_special_condition_for_native_trans), R0); + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, SharedRuntime::check_special_condition_for_native_trans), R0); __ mr(R3_ARG1, R16_thread); __ call_c(call_target_address); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index c9b8e8252675..ae86f80cff4c 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2617,8 +2617,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, } // Publish thread state - // Transition from _thread_in_native to _thread_in_vm. - __ li(R0, _thread_in_vm); + // Transition from _thread_in_native. + __ li(R0, _thread_in_Java); __ release(); // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); __ stw(R0, thread_(thread_state)); @@ -2642,7 +2642,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, Register suspend_flags = r_temp_6; // No synchronization in progress nor yet synchronized - // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path). __ safepoint_poll(sync, sync_state, true /* at_return */, false /* in_nmethod */); // Not suspended. @@ -2656,28 +2655,15 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // lets us share the oopMap we used when we went native rather than create // a distinct one for this pc. __ bind(sync); - __ isync(); address entry_point = - CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans); + CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans); save_native_result(masm, ret_type, workspace_slot_offset); __ call_VM_leaf(entry_point, R16_thread); restore_native_result(masm, ret_type, workspace_slot_offset); __ bind(no_block); - // Publish thread state. - // -------------------------------------------------------------------------- - - // Thread state is _thread_in_vm. Any safepoint blocking has - // already happened so we can now change state to _thread_in_Java. - - // Transition from _thread_in_vm to _thread_in_Java. - __ li(R0, _thread_in_Java); - __ lwsync(); // Acquire safepoint and suspend state, release thread state. - // TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); - __ stw(R0, thread_(thread_state)); - // Check preemption for Object.wait() if (method->is_object_wait0()) { Label not_preempted; diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 9e8cb838955c..69ff7c2a6a65 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1487,7 +1487,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // We use release_store_fence to update values like the thread state, where // we don't want the current thread to continue until all our prior memory // accesses (including the new thread state) are visible to other threads. - __ li(R0/*thread_state*/, _thread_in_vm); + __ li(R0/*thread_state*/, _thread_in_Java); __ release(); __ stw(R0/*thread_state*/, thread_(thread_state)); if (!UseSystemMemoryBarrier) { @@ -1498,10 +1498,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // (a new safepoint can not start since we entered _thread_in_vm). // We must check here because a current safepoint could be in progress. - // Acquire isn't strictly necessary here because of the fence, but - // sync_state is declared to be volatile, so we do it anyway - // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path). - Label do_safepoint, sync_check_done; // No synchronization in progress nor yet synchronized. __ safepoint_poll(do_safepoint, sync_state, true /* at_return */, false /* in_nmethod */); @@ -1513,13 +1509,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ beq(CR1, sync_check_done); __ bind(do_safepoint); - __ isync(); // Block. We do the call directly and leave the current // last_Java_frame setup undisturbed. We must save any possible // native result across the call. No oop is present. __ mr(R3_ARG1, R16_thread); - __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ call_c(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); __ bind(sync_check_done); @@ -1540,14 +1535,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // On PPC64, we have stored the result directly after the native call. //============================================================================= - // Back in Java - - // We use release_store_fence to update values like the thread state, where - // we don't want the current thread to continue until all our prior memory - // accesses (including the new thread state) are visible to other threads. - __ li(R0/*thread_state*/, _thread_in_Java); - __ lwsync(); // Acquire safepoint and suspend state, release thread state. - __ stw(R0/*thread_state*/, thread_(thread_state)); if (support_vthread_preemption) { // Check preemption for Object.wait() diff --git a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp index beb8f457e9d5..e1511f5b7f34 100644 --- a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp @@ -304,12 +304,14 @@ void DowncallLinker::StubGenerator::generate() { Label L_reguard; Label L_after_reguard; if (_needs_transition) { + __ block_comment("{ thread native2java"); // Restore cpu control state after JNI call __ restore_cpu_control_state_after_jni(t0); - __ block_comment("{ thread native2java"); - __ mv(t0, _thread_in_vm); - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + // change thread state + __ mv(t1, _thread_in_Java); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -322,11 +324,6 @@ void DowncallLinker::StubGenerator::generate() { __ bind(L_after_safepoint_poll); - // change thread state - __ mv(t0, _thread_in_Java); - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); - __ block_comment("reguard stack check"); __ lbu(t0, Address(xthread, JavaThread::stack_guard_state_offset())); __ mv(t1, StackOverflow::stack_guard_yellow_reserved_disabled); @@ -353,7 +350,7 @@ void DowncallLinker::StubGenerator::generate() { __ mv(c_rarg0, xthread); assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); - __ rt_call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); if (should_save_return_value) { out_reg_spiller.generate_fill(_masm, out_spill_offset); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 14649fab5b8c..f1bc7fc0d5e3 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1817,9 +1817,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label safepoint_in_progress, safepoint_in_progress_done; - __ mv(t0, _thread_in_vm); - - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + // change thread state + __ mv(t1, _thread_in_Java); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -1834,12 +1835,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ bind(safepoint_in_progress_done); } - // change thread state - __ la(t1, Address(xthread, JavaThread::thread_state_offset())); - __ mv(t0, _thread_in_Java); - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sw(t0, Address(t1)); - if (method->is_object_wait0()) { // Check preemption for Object.wait() __ ld(t1, Address(xthread, JavaThread::preempt_alternate_return_offset())); @@ -2040,7 +2035,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, #ifndef PRODUCT assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); #endif - __ rt_call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); // Restore any method result value restore_native_result(masm, ret_type, stack_slots); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index ef23498da5c7..bf552678f965 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1210,11 +1210,9 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ push(ltos); // change thread state - // Force all preceding writes to be observed prior to thread state change + __ mv(t1, _thread_in_Java); __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - - __ mv(t0, _thread_in_vm); - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -1236,19 +1234,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // hand. // __ mv(c_rarg0, xthread); - __ rt_call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); __ get_method(xmethod); __ reinit_heapbase(); __ bind(Continue); } - // change thread state - // Force all preceding writes to be observed prior to thread state change - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - - __ mv(t0, _thread_in_Java); - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); - // Check preemption for Object.wait() Label not_preempted; __ ld(t1, Address(xthread, JavaThread::preempt_alternate_return_offset())); diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index a10d4c1833d1..49d7ab0d487e 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -247,7 +247,8 @@ void DowncallLinker::StubGenerator::generate() { if (_needs_transition) { __ block_comment("thread_native2java {"); - __ set_thread_state(_thread_in_vm); + // change thread state + __ set_thread_state(_thread_in_Java); if (!UseSystemMemoryBarrier) { __ z_fence(); // Order state change wrt. safepoint poll. @@ -260,9 +261,6 @@ void DowncallLinker::StubGenerator::generate() { __ bind(L_after_safepoint_poll); - // change thread state - __ set_thread_state(_thread_in_Java); - __ block_comment("reguard_stack_check {"); __ z_cli(Address(Z_thread, JavaThread::stack_guard_state_offset() + in_ByteSize(sizeof(StackOverflow::StackGuardState) - 1)), @@ -288,7 +286,7 @@ void DowncallLinker::StubGenerator::generate() { // Need to save the native result registers around any runtime calls. out_reg_spiller.generate_spill(_masm, out_spill_offset); - __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, JavaThread::check_special_condition_for_native_trans)); + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, SharedRuntime::check_special_condition_for_native_trans)); __ z_lgr(Z_ARG1, Z_thread); __ call(call_target_address); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index af2e3c3490f5..aad194900450 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2745,8 +2745,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, break; } - // Transition from _thread_in_native to _thread_in_vm. - __ set_thread_state(_thread_in_vm); + // Transition from _thread_in_native to _thread_in_Java. + __ set_thread_state(_thread_in_Java); + + // Force this write out before the read below. + if (!UseSystemMemoryBarrier) { + __ z_fence(); + } // Safepoint synchronization //-------------------------------------------------------------------- @@ -2760,11 +2765,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, save_native_result(masm, ret_type, workspace_slot_offset); // Make Z_R2 available as work reg. - // Force this write out before the read below. - if (!UseSystemMemoryBarrier) { - __ z_fence(); - } - __ safepoint_poll(sync, Z_R1); __ load_and_test_int(Z_R0, Address(Z_thread, JavaThread::suspend_flags_offset())); @@ -2776,9 +2776,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // a distinct one for this pc. // __ bind(sync); - __ z_acquire(); - address entry_point = CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans); + address entry_point = CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans); __ call_VM_leaf(entry_point, Z_thread); @@ -2786,13 +2785,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, restore_native_result(masm, ret_type, workspace_slot_offset); } - //-------------------------------------------------------------------- - // Thread state is _thread_in_vm. Any safepoint blocking has - // already happened so we can now change state to _thread_in_Java. - //-------------------------------------------------------------------- - // Transition from _thread_in_vm to _thread_in_Java. - __ set_thread_state(_thread_in_Java); - // Check preemption for Object.wait() if (method->is_object_wait0()) { NearLabel not_preempted; diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index c0a1b06954da..ddcba7b25339 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -1575,13 +1575,14 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // In order for GC to work, don't clear the last_Java_sp until after // blocking. - __ set_thread_state(_thread_in_vm); + // Transition from _thread_in_native to _thread_in_Java. + // Force this write out before the read below; + __ set_thread_state(_thread_in_Java); if (!UseSystemMemoryBarrier) { __ z_fence(); } - // Now before we return to java we must look for a current safepoint - // (a new safepoint can not start since we entered _thread_in_vm). + // Now before we return to java we must look for a current safepoint. // We must check here because a current safepoint could be in progress. // Check for safepoint operation in progress and/or pending suspend requests. @@ -1593,17 +1594,13 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ z_bre(Continue); // 0 -> no flag set -> not suspended __ bind(do_safepoint); __ z_lgr(Z_ARG1, Z_thread); - __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ call_c(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); __ bind(Continue); } //============================================================================= // Back in Interpreter Frame. - // We are in _thread_in_vm here and back in the normal - // interpreter frame. We don't have to do anything special about - // safepoints and we can switch to Java mode anytime we are ready. - // Note: frame::interpreter_frame_result has a dependency on how the // method result is saved across the call to post_method_exit. For // native methods it assumes that the non-FPU/non-void result is @@ -1614,10 +1611,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { //============================================================================= // Back in Java. - // Memory ordering: Z does not reorder store/load with subsequent - // load. That's strong enough. - __ set_thread_state(_thread_in_Java); - __ reset_last_Java_frame(); // We reset the JNI handle block only after unboxing the result; see below. diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp index 98b52e1d6288..5d6286786683 100644 --- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp @@ -310,7 +310,8 @@ void DowncallLinker::StubGenerator::generate() { __ block_comment("{ thread native2java"); __ restore_cpu_control_state_after_jni(rscratch1); - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_vm); + // change thread state + __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -325,9 +326,6 @@ void DowncallLinker::StubGenerator::generate() { __ bind(L_after_safepoint_poll); - // change thread state - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); - __ block_comment("reguard stack check"); __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_yellow_reserved_disabled); __ jcc(Assembler::equal, L_reguard); @@ -351,7 +349,7 @@ void DowncallLinker::StubGenerator::generate() { } __ mov(c_rarg0, r15_thread); - runtime_call(_masm, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + runtime_call(_masm, CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans)); if (should_save_return_value) { out_reg_spiller.generate_fill(_masm, out_spill_rsp_offset); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 36cb8d41e820..0eb629f6ee8e 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2456,7 +2456,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, default : ShouldNotReachHere(); } - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_vm); + // change thread state + __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -2488,7 +2489,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ mov(r12, rsp); // remember sp __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows __ andptr(rsp, -16); // align stack as required by ABI - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans))); __ mov(rsp, r12); // restore sp __ reinit_heapbase(); // Restore any method result value @@ -2496,9 +2497,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ bind(Continue); } - // change thread state - __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); - if (method->is_object_wait0()) { // Check preemption for Object.wait() __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 631d23801d33..38dfe1e171b0 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -955,8 +955,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ push(ltos); // change thread state - __ movl(Address(thread, JavaThread::thread_state_offset()), - _thread_in_vm); + __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); // Force this write out before the read below if (!UseSystemMemoryBarrier) { @@ -987,15 +986,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM) __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows __ andptr(rsp, -16); // align stack as required by ABI - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::check_special_condition_for_native_trans))); __ mov(rsp, r12); // restore sp __ reinit_heapbase(); __ bind(Continue); } - // change thread state - __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); - // Check preemption for Object.wait() Label not_preempted; __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 89a021ddb294..cc2f5ff0f2e2 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -41,6 +41,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/sharedRuntime.hpp" #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "utilities/debug.hpp" @@ -427,18 +428,16 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // ThreadStateTransition::transition_from_native() cannot be used // here because it does not check for asynchronous exceptions. // We have to manage the transition ourself. - thread->set_thread_state_fence(_thread_in_vm); + thread->set_thread_state_fence(_thread_in_Java); // Handle safepoint operations, pending suspend requests, // and pending asynchronous exceptions. if (SafepointMechanism::should_process(thread) || thread->has_special_condition_for_native_trans()) { - JavaThread::check_special_condition_for_native_trans(thread); + SharedRuntime::check_special_condition_for_native_trans(thread); CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops()); } - // Finally we can change the thread state to _thread_in_Java. - thread->set_thread_state(_thread_in_Java); fixup_after_potential_safepoint(); // Notify the stack watermarks machinery that we are unwinding. diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 7809e66058fb..be5478829f07 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -104,7 +104,9 @@ class ThreadStateTransition : public StackObj { thread->set_thread_state(_thread_in_vm); } SafepointMechanism::process_if_requested_with_exit_check(thread, to != _thread_in_Java ? false : check_asyncs); - thread->set_thread_state(to); + if (to != _thread_in_vm) { + thread->set_thread_state(to); + } } static inline void transition_from_vm(JavaThread *thread, JavaThreadState to, bool check_asyncs = true) { diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index c14126b6c5dc..90b6a256715e 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -290,8 +290,15 @@ void JavaThread::check_for_valid_safepoint_state() { // are held. check_possible_safepoint(); - if (thread_state() != _thread_in_vm) { - fatal("LEAF method calling lock?"); + switch (thread_state()) { + case _thread_in_vm: + // In debug builds, leaf entries use NoHandleMark and NoSafepointVerifier (checked above). + if (handle_area()->no_handle_mark_active()) { + fatal("LEAF method calling lock?"); + } + break; + default: + fatal("illegal thread state %d, LEAF method calling lock?", thread_state()); } if (GCALotAtAllSafepoints) { @@ -1096,24 +1103,6 @@ void JavaThread::verify_not_published() { } #endif -// Slow path when the native==>Java barriers detect a safepoint/handshake is -// pending, when _suspend_flags is non-zero or when we need to process a stack -// watermark. Also check for pending async exceptions (except unsafe access error). -void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) { - assert(thread->thread_state() == _thread_in_vm, "wrong state"); - assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition"); - - // Enable WXWrite: called directly from interpreter native wrapper. - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread)); - - SafepointMechanism::process_if_requested_with_exit_check(thread, true /* check asyncs */); - - // After returning from native, it could be that the stack frames are not - // yet safe to use. We catch such situations in the subsequent stack watermark - // barrier, which will trap unsafe stack frames. - StackWatermarkSet::before_unwind(thread); -} - #ifndef PRODUCT // Deoptimization // Function for testing deoptimization diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 8418b62b1fec..f3e3617a40b9 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -666,9 +666,6 @@ class JavaThread: public Thread { bool is_suspended() { return _suspend_resume_manager.is_suspended(); } SuspendResumeManager* suspend_resume_manager() { return &_suspend_resume_manager; } - // Check for async exception in addition to safepoint. - static void check_special_condition_for_native_trans(JavaThread *thread); - // Synchronize with another thread that is deoptimizing objects of the // current thread, i.e. reverts optimizations based on escape analysis. void wait_for_object_deoptimization(); diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index 293452ed9ccc..9d0870e7d930 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -142,25 +142,15 @@ inline JavaThread::NoAsyncExceptionDeliveryMark::~NoAsyncExceptionDeliveryMark() } inline JavaThreadState JavaThread::thread_state() const { -#if defined(PPC64) || defined (AARCH64) || defined(RISCV64) - // Use membars when accessing volatile _thread_state. See - // Threads::create_vm() for size checks. + // Use membars when accessing volatile _thread_state. return AtomicAccess::load_acquire(&_thread_state); -#else - return AtomicAccess::load(&_thread_state); -#endif } inline void JavaThread::set_thread_state(JavaThreadState s) { assert(current_or_null() == nullptr || current_or_null() == this, "state change should only be called by the current thread"); -#if defined(PPC64) || defined (AARCH64) || defined(RISCV64) - // Use membars when accessing volatile _thread_state. See - // Threads::create_vm() for size checks. + // Use membars when accessing volatile _thread_state. AtomicAccess::release_store(&_thread_state, s); -#else - AtomicAccess::store(&_thread_state, s); -#endif } inline void JavaThread::set_thread_state_fence(JavaThreadState s) { diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index b770b638ff39..0a239388d0e4 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -4219,3 +4219,24 @@ JRT_BLOCK_ENTRY(void, SharedRuntime::store_inline_type_fields_to_buf(JavaThread* JRT_BLOCK_END; } JRT_END + +// Slow path when the native==>Java barriers detect a safepoint/handshake is +// pending, when _suspend_flags is non-zero or when we need to process a stack +// watermark. Also check for pending async exceptions (except unsafe access error). +JRT_BLOCK_ENTRY(void, SharedRuntime::check_special_condition_for_native_trans(JavaThread *current)) + assert(!current->has_last_Java_frame() || current->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition"); + + JRT_BLOCK + // This block looks empty, but the ThreadInVMfromJava hidden in the macro + // does all the heavy lifting. + + // On block exit, process safepoint, check for pending async exceptions, etc + JRT_BLOCK_END + + // After returning from native, it could be that the stack frames are not + // yet safe to use. We catch such situations in the subsequent stack watermark + // barrier, which will trap unsafe stack frames. + // This must happen after processing the safepoint, otherwise preconditions for + // before_unwind are not met. + StackWatermarkSet::before_unwind(current); +JRT_END diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 5accc54a629e..c0139870df90 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -690,6 +690,10 @@ class SharedRuntime: AllStatic { #endif // PRODUCT static void print_statistics() PRODUCT_RETURN; + + // native --> Java safepoint entry point + // Check for async exception in addition to safepoint. + static void check_special_condition_for_native_trans(JavaThread *current); }; From 4f75948d1fca2ebc3b71fc93116698b797dc6c0a Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 2 Sep 2026 01:03:53 +0000 Subject: [PATCH 186/223] 8391236: RISC-V: Save a jump in string_indexof_char intrinsic Reviewed-by: fyang, gcao, aivy --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 7725b2dfca51..edd018c733f5 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -514,19 +514,20 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register tmp3, Register tmp4, bool isL) { - Label CH1_LOOP, HIT, NOMATCH, DONE, SHORT; + Label CH1_LOOP, HIT, DONE, SHORT; Register ch1 = t0; Register orig_cnt = t1; - Register mask1 = tmp3; + Register mask1 = tmp1; Register mask2 = tmp2; - Register match_mask = tmp1; + Register match_mask = tmp3; Register loop_step = tmp4; Register trailing_chars = tmp4; Register unaligned_chars = tmp4; Register start_index = tmp4; BLOCK_COMMENT("string_indexof_char {"); - beqz(cnt1, NOMATCH); + mv(result, -1); + beqz(cnt1, DONE); subi(t0, cnt1, isL ? 32 : 16); mv(start_index, zr); @@ -575,13 +576,13 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, bind(CH1_LOOP); ld(ch1, Address(str1)); - addi(str1, str1, 8); - subi(cnt1, cnt1, 8); compute_match_mask(ch1, ch, match_mask, mask1, mask2); bnez(match_mask, HIT); + addi(str1, str1, 8); + subi(cnt1, cnt1, 8); bge(cnt1, loop_step, CH1_LOOP); - beqz(cnt1, NOMATCH); + beqz(cnt1, DONE); if (!isL) { srli(cnt1, cnt1, 1); } @@ -601,9 +602,8 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, bind(HIT); // count bits of trailing zero chars - ctzc_bits(trailing_chars, match_mask, isL, ch1, result); + ctzc_bits(trailing_chars, match_mask, isL, mask1, mask2); srli(trailing_chars, trailing_chars, 3); - addi(cnt1, cnt1, 8); // match case if (!isL) { @@ -613,10 +613,6 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, sub(result, orig_cnt, cnt1); add(result, result, trailing_chars); - j(DONE); - - bind(NOMATCH); - mv(result, -1); bind(DONE); BLOCK_COMMENT("} string_indexof_char"); From 08e26060dfe9984b77b70c477962ac4b68c30c41 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 2 Sep 2026 04:21:02 +0000 Subject: [PATCH 187/223] 8390818: Set UseFPUForSpilling default off on AMD Zen3+ targets Reviewed-by: mhaessig, qamai --- src/hotspot/cpu/x86/vm_version_x86.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 12cdadf026b6..61b012e74351 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1576,12 +1576,18 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { FLAG_SET_DEFAULT(UseUnalignedLoadStores, true); } + } + #ifdef COMPILER2 + // Enable UseFPUForSpilling on Zen1/Zen2 (family 0x17) and Hygon Dhyana (family 0x18). + // On Zen3 (family 0x19) and beyond it should be default off. + if (cpu_family() >= 0x17 && cpu_family() < 0x19) { if (supports_sse4_2() && FLAG_IS_DEFAULT(UseFPUForSpilling)) { FLAG_SET_DEFAULT(UseFPUForSpilling, true); } -#endif } +#endif // COMPILER2 + } if (is_intel()) { // Intel cpus specific settings From 4860fca701f7d1aa6e771197ac701a4ddf5f9ec5 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 2 Sep 2026 05:21:40 +0000 Subject: [PATCH 188/223] 8391280: [Valhalla] PhaseMacroExpand::expand_flatarraycheck_node asserts with "Mixing array and klass inputs" Reviewed-by: mchevalier, kvn --- src/hotspot/share/opto/library_call.cpp | 10 +- src/hotspot/share/opto/macro.cpp | 53 ++++--- src/hotspot/share/opto/subnode.hpp | 4 +- .../TestFlatArrayCheckExpansion.java | 130 ++++++++++++++++++ 4 files changed, 173 insertions(+), 24 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index c16888ddf97e..7dc78e959b57 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4937,7 +4937,7 @@ bool LibraryCallKit::inline_getArrayProperties(ArrayPropertiesCheck check) { Node* bol; switch(check) { case IsFlat: - bol = flat_array_test(load_object_klass(array)); + bol = flat_array_test(array); break; case IsNullRestricted: bol = null_free_array_test(array); @@ -4947,8 +4947,7 @@ bool LibraryCallKit::inline_getArrayProperties(ArrayPropertiesCheck check) { // 1. If not flat, then atomic, or else... RegionNode* atomic_region = new RegionNode(1); RegionNode* non_atomic_region = new RegionNode(1); - Node* array_klass = load_object_klass(array); - Node* is_flat_bol = flat_array_test(array_klass); + Node* is_flat_bol = flat_array_test(array); IfNode* iff_is_flat = create_and_xform_if(control(), is_flat_bol, PROB_FAIR, COUNT_UNKNOWN); atomic_region->add_req(_gvn.transform(new IfFalseNode(iff_is_flat))); set_control(_gvn.transform(new IfTrueNode(iff_is_flat))); @@ -4957,6 +4956,7 @@ bool LibraryCallKit::inline_getArrayProperties(ArrayPropertiesCheck check) { Node* layout_kind = atomic_layout_array_test_and_get_layout_kind(array, atomic_region); // 3. ...if the element type is naturally atomic and null-free OR empty and nullable, then atomic, or else... + Node* array_klass = load_object_klass(array); int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* array_element_klass_addr = off_heap_plus_addr(array_klass, element_klass_offset); Node* array_element_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), array_element_klass_addr, _gvn.type(array_klass)->is_klassptr())); @@ -5263,7 +5263,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { if (Arguments::is_valhalla_enabled()) { // Handle inline type arrays // TODO 8251971 This is too strong - generate_fair_guard(flat_array_test(load_object_klass(original)), bailout); + generate_fair_guard(flat_array_test(original), bailout); generate_fair_guard(flat_array_test(refined_klass_node), bailout); generate_fair_guard(null_free_array_test(original), bailout); } @@ -6320,7 +6320,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { (ary_ptr == nullptr || (!ary_ptr->is_not_flat() && (!ary_ptr->is_flat() || ary_ptr->elem()->inline_klass()->contains_oops())))) { // Flat inline type array may have object field that would require a // write barrier. Conservatively, go to slow path. - generate_fair_guard(flat_array_test(obj_klass), slow_region); + generate_fair_guard(flat_array_test(obj), slow_region); } if (!stopped()) { diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index ccf2cb0382ff..06dff588c852 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -3076,20 +3076,42 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { _igvn.replace_node(check, C->top()); } -// FlatArrayCheckNode (array1 array2 ...) is expanded into: +// FlatArrayCheckNode inputs must be homogeneous: either all array inputs +// (array1 array2 ...) or all klass inputs (klass1 klass2 ...). +// +// For array inputs whose users are all If nodes, the check is expanded using +// mark words: // // long mark = array1.mark | array2.mark | ...; // long locked_bit = markWord::unlocked_value & array1.mark & array2.mark & ...; // if (locked_bit == 0) { -// // One array is locked, load prototype header from the klass -// mark = array1.klass.proto | array2.klass.proto | ... +// // One array is locked, load its prototype header from the klass +// mark = array1.klass.proto | array2.klass.proto | ...; // } // if ((mark & markWord::flat_array_bit_in_place) == 0) { -// ... +// ... +// } +// +// For klass inputs, and for array inputs with a non-If user, the check is +// expanded using the klass layout helpers. For array inputs, the klasses are +// loaded first: +// +// int layout = klass1.layout_helper | klass2.layout_helper | ...; +// if ((layout & Klass::_lh_array_tag_flat_value_bit_inplace) == 0) { +// ... // } void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { - bool array_inputs = _igvn.type(check->in(FlatArrayCheckNode::ArrayOrKlass))->isa_oopptr() != nullptr; - if (array_inputs) { + bool use_mark_word = _igvn.type(check->in(FlatArrayCheckNode::ArrayOrKlass))->isa_oopptr() != nullptr; + Node* bol = check->unique_out(); + for (DUIterator_Fast imax, i = bol->fast_outs(imax); i < imax; i++) { + if (!bol->fast_out(i)->is_If()) { + // No control input, fall back to layout helper check + use_mark_word = false; + break; + } + } + + if (use_mark_word) { Node* mark = MakeConX(0); Node* locked_bit = MakeConX(markWord::unlocked_value); Node* mem = check->in(FlatArrayCheckNode::Memory); @@ -3108,10 +3130,9 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { Node* is_unlocked = _igvn.transform(new BoolNode(cmp, BoolTest::ne)); // BoolNode might be shared, replace each if user - Node* old_bol = check->unique_out(); - assert(old_bol->is_Bool() && old_bol->as_Bool()->_test._test == BoolTest::ne, "unexpected condition"); - for (DUIterator_Last imin, i = old_bol->last_outs(imin); i >= imin; --i) { - IfNode* old_iff = old_bol->last_out(i)->as_If(); + assert(bol->is_Bool() && bol->as_Bool()->_test._test == BoolTest::ne, "unexpected condition"); + for (DUIterator_Last imin, i = bol->last_outs(imin); i >= imin; --i) { + IfNode* old_iff = bol->last_out(i)->as_If(); Node* ctrl = old_iff->in(0); RegionNode* region = new RegionNode(3); Node* mark_phi = new PhiNode(region, TypeX_X); @@ -3170,18 +3191,16 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { } Node* masked = transform_later(new AndINode(lhs, intcon(Klass::_lh_array_tag_flat_value_bit_inplace))); Node* cmp = transform_later(new CmpINode(masked, intcon(0))); - Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq)); + Node* new_bol = transform_later(new BoolNode(cmp, BoolTest::eq)); Node* m2b = transform_later(new Conv2BNode(masked)); // The matcher expects the input to If/CMove nodes to be produced by a Bool(CmpI..) // pattern, but the input to other potential users (e.g. Phi) to be some // other pattern (e.g. a Conv2B node, possibly idealized as a CMoveI). - Node* old_bol = check->unique_out(); - for (DUIterator_Last imin, i = old_bol->last_outs(imin); i >= imin; --i) { - Node* user = old_bol->last_out(i); + for (DUIterator_Last imin, i = bol->last_outs(imin); i >= imin; --i) { + Node* user = bol->last_out(i); for (uint j = 0; j < user->req(); j++) { - Node* n = user->in(j); - if (n == old_bol) { - _igvn.replace_input_of(user, j, (user->is_If() || user->is_CMove()) ? bol : m2b); + if (user->in(j) == bol) { + _igvn.replace_input_of(user, j, (user->is_If() || user->is_CMove()) ? new_bol : m2b); } } } diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index b59b9b9bf532..3b3877f35daf 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -311,8 +311,8 @@ class CmpD3Node : public CmpDNode { }; //--------------------------FlatArrayCheckNode--------------------------------- -// Returns true if one of the input array objects or array klass ptrs (there -// can be multiple) is flat. +// Returns true if one of the inputs is flat. There can be multiple inputs, but +// all must be of the same kind: either array objects or array klass ptrs. class FlatArrayCheckNode : public CmpNode { public: enum { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java new file mode 100644 index 000000000000..e3afb9138f59 --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.valhalla.inlinetypes; + +import jdk.internal.value.ValueClass; +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8391280 + * @summary Test macro expansion of merged flat-array checks with array and klass inputs + * @enablePreview + * @library /test/lib + * @modules java.base/jdk.internal.value + * @run main ${test.main.class} + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * ${test.main.class} + */ +public class TestFlatArrayCheckExpansion { + + static int test1(Object[] array) { + int res = 0; + for (int i = 0; i < 4; i++) { + // FlatArrayCheckNode with a Klass* input + if (ValueClass.isFlatArray(array)) { + res += 1; + } else { + res += 2; + } + // FlatArrayCheckNode with an oop input + res += (Integer)array[i]; + } + return res; + } + + // Same as test1 but different order of checks + static int test2(Object[] array) { + int res = 0; + for (int i = 0; i < 4; i++) { + // FlatArrayCheckNode with an oop input + res += (Integer)array[i]; + // FlatArrayCheckNode with a Klass* input + if (ValueClass.isFlatArray(array)) { + res += 1; + } else { + res += 2; + } + } + return res; + } + + // Same as test1 but with two different arrays + static int test3(Object[] array1, Object[] array2) { + int res = 0; + for (int i = 0; i < 4; i++) { + // FlatArrayCheckNode with a Klass* input + if (ValueClass.isFlatArray(array1)) { + res += 1; + } else { + res += 2; + } + // FlatArrayCheckNode with an oop input + res += (Integer)array2[i]; + } + return res; + } + + // Same as test2 but with two different arrays + static int test4(Object[] array1, Object[] array2) { + int res = 0; + for (int i = 0; i < 4; i++) { + // FlatArrayCheckNode with an oop input + res += (Integer)array2[i]; + // FlatArrayCheckNode with a Klass* input + if (ValueClass.isFlatArray(array1)) { + res += 1; + } else { + res += 2; + } + } + return res; + } + + public static void main(String[] args) { + Object[] refArray = {1, 2, 3, 4}; + Integer[] flatArray = {1, 2, 3, 4}; + boolean isFlat = ValueClass.isFlatArray(flatArray); + + for (int i = 0; i < 50_000; i++) { + Asserts.assertEQ(test1(refArray), 18); + Asserts.assertEQ(test1(flatArray), isFlat ? 14 : 18); + + Asserts.assertEQ(test2(refArray), 18); + Asserts.assertEQ(test2(flatArray), isFlat ? 14 : 18); + + Asserts.assertEQ(test3(refArray, refArray), 18); + Asserts.assertEQ(test3(refArray, flatArray), 18); + Asserts.assertEQ(test3(flatArray, refArray), isFlat ? 14 : 18); + Asserts.assertEQ(test3(flatArray, flatArray), isFlat ? 14 : 18); + + Asserts.assertEQ(test4(refArray, refArray), 18); + Asserts.assertEQ(test4(refArray, flatArray), 18); + Asserts.assertEQ(test4(flatArray, refArray), isFlat ? 14 : 18); + Asserts.assertEQ(test4(flatArray, flatArray), isFlat ? 14 : 18); + } + } +} + From e5b7c22eb5af7fe8d007597cde2d80700c79e68d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 2 Sep 2026 06:48:54 +0000 Subject: [PATCH 189/223] 8391349: G1: Clean up G1HeapRegionRemSet files Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CodeRootSet.cpp | 14 -------- src/hotspot/share/gc/g1/g1CodeRootSet.hpp | 3 -- .../share/gc/g1/g1HeapRegionRemSet.cpp | 32 +------------------ .../share/gc/g1/g1HeapRegionRemSet.hpp | 22 ++++--------- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 12 +++---- .../gtest/gc/g1/test_g1CodeRootSet.cpp | 15 ++------- 6 files changed, 16 insertions(+), 82 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp index 7f1dec462d4f..75e9b1d2b71b 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp @@ -127,15 +127,6 @@ class G1CodeRootSetHashTable : public CHeapObj { } } - bool remove(nmethod* method) { - HashTableLookUp lookup(method); - bool removed = _table.remove(Thread::current(), lookup); - if (removed) { - _num_entries.sub_then_fetch(1u); - } - return removed; - } - bool contains(nmethod* method) { HashTableLookUp lookup(method); HashTableIgnore ignore; @@ -281,11 +272,6 @@ G1CodeRootSet::~G1CodeRootSet() { delete _table; } -bool G1CodeRootSet::remove(nmethod* method) { - assert(!_is_iterating, "should not mutate while iterating the table"); - return _table->remove(method); -} - void G1CodeRootSet::bulk_remove() { assert(!_is_iterating, "should not mutate while iterating the table"); _table->bulk_remove(); diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp index b298bbfb9148..c01a4a8396a5 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp @@ -43,7 +43,6 @@ class G1CodeRootSet { ~G1CodeRootSet(); void add(nmethod* method); - bool remove(nmethod* method); void bulk_remove(); // Notify the code root set that we are about to add the given // number of code roots. Only to be used during safepoint, not @@ -59,8 +58,6 @@ class G1CodeRootSet { // Remove all nmethods which no longer contain pointers into our "owner" region. void clean(G1HeapRegion* owner); - bool is_empty() { return length() == 0;} - // Length in elements size_t length() const; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 94b8633cd8ff..a965859a4146 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -22,24 +22,8 @@ * */ -#include "gc/g1/g1BlockOffsetTable.inline.hpp" -#include "gc/g1/g1CardSetContainers.inline.hpp" -#include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1ConcurrentRefine.hpp" -#include "gc/g1/g1HeapRegionManager.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" -#include "memory/allocation.hpp" -#include "memory/padded.inline.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/globals_extension.hpp" -#include "runtime/java.hpp" -#include "runtime/mutexLocker.hpp" -#include "utilities/bitMap.inline.hpp" -#include "utilities/debug.hpp" -#include "utilities/formatBuffer.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/powerOfTwo.hpp" +#include "utilities/ostream.hpp" HeapWord* G1HeapRegionRemSet::_heap_base_address = nullptr; @@ -91,26 +75,12 @@ void G1HeapRegionRemSet::print_static_mem_size(outputStream* out) { } // Code roots support -// -// The code root set is protected by two separate locking schemes -// When at safepoint the per-hrrs lock must be held during modifications -// except when doing a full gc. -// When not at safepoint the CodeCache_lock must be held during modifications. void G1HeapRegionRemSet::add_code_root(nmethod* nm) { assert(nm != nullptr, "sanity"); _code_roots.add(nm); } -void G1HeapRegionRemSet::remove_code_root(nmethod* nm) { - assert(nm != nullptr, "sanity"); - - _code_roots.remove(nm); - - // Check that there were no duplicates - guarantee(!_code_roots.contains(nm), "duplicate entry found"); -} - void G1HeapRegionRemSet::bulk_remove_code_roots() { _code_roots.bulk_remove(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 70b32effd9d5..69f55228af54 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -29,12 +29,7 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CodeRootSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/safepoint.hpp" -#include "utilities/bitMap.hpp" -class G1CardSetMemoryManager; -class G1CSetCandidateGroup; class G1FromCardCache; class outputStream; @@ -43,7 +38,6 @@ class G1HeapRegionRemSet : public CHeapObj { // the region that owns this RSet. G1CodeRootSet _code_roots; - // The collection set groups to which the region owning this RSet is assigned. G1CSetCandidateGroup* _cset_group; // Cached value of heap base address. @@ -59,14 +53,14 @@ class G1HeapRegionRemSet : public CHeapObj { return cset_group()->card_set(); } -public: - G1HeapRegionRemSet(); - ~G1HeapRegionRemSet(); - bool card_set_is_empty() const { return !has_cset_group() || card_set()->is_empty(); } +public: + G1HeapRegionRemSet(); + ~G1HeapRegionRemSet(); + void install_cset_group(G1CSetCandidateGroup* cset_group) { assert(cset_group != nullptr, "pre-condition"); assert(_cset_group == nullptr, "pre-condition"); @@ -101,7 +95,7 @@ class G1HeapRegionRemSet : public CHeapObj { return (code_roots_list_length() == 0) && card_set()->occupancy_less_or_equal_to(occ); } - // Iterate the card based remembered set for merging them into the card table. + // Iterate the cards in this remembered set for merging them into the card table. // The passed closure must be a CardOrRangeVisitor; we use a template parameter // to pass it in to facilitate inlining as much as possible. template @@ -115,7 +109,6 @@ class G1HeapRegionRemSet : public CHeapObj { return card_set()->occupied(); } - static void initialize(MemRegion reserved); inline uintptr_t to_card(OopOrNarrowOopStar from) const; @@ -172,10 +165,9 @@ class G1HeapRegionRemSet : public CHeapObj { inline void print_info(outputStream* st, OopOrNarrowOopStar from); - // Routines for managing the list of code roots that point into - // the heap region that owns this RSet. + // Routines for managing the code roots that point into the heap region + // that owns this RSet. void add_code_root(nmethod* nm); - void remove_code_root(nmethod* nm); void bulk_remove_code_roots(); void prepare_for_adding_code_roots(size_t num_code_roots); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index fb63bccd957e..25b1fbebfff5 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -22,16 +22,16 @@ * */ -#ifndef SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP -#define SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP +#ifndef SHARE_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP +#define SHARE_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP #include "gc/g1/g1HeapRegionRemSet.hpp" #include "gc/g1/g1CardSet.inline.hpp" -#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectionSetCandidates.hpp" #include "gc/g1/g1FromCardCache.inline.hpp" -#include "gc/g1/g1HeapRegion.inline.hpp" -#include "utilities/bitMap.inline.hpp" +#include "gc/shared/cardTable.hpp" +#include "runtime/safepoint.hpp" void G1HeapRegionRemSet::set_state_untracked() { guarantee(SafepointSynchronize::is_at_safepoint() || !is_tracked(), @@ -144,4 +144,4 @@ void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) { card_set()->print_info(st, to_card(from)); } -#endif // SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP +#endif // SHARE_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP diff --git a/test/hotspot/gtest/gc/g1/test_g1CodeRootSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CodeRootSet.cpp index 80f3f33bf052..389a8ae49352 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CodeRootSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CodeRootSet.cpp @@ -27,7 +27,7 @@ TEST_VM(G1CodeRootSet, g1_code_cache_rem_set) { G1CodeRootSet root_set; - ASSERT_TRUE(root_set.is_empty()) << "Code root set must be initially empty " + ASSERT_TRUE(root_set.length() == 0) << "Code root set must be initially empty " "but is not."; root_set.add((nmethod*) 1); @@ -51,18 +51,7 @@ TEST_VM(G1CodeRootSet, g1_code_cache_rem_set) { << "After adding in total " << num_to_add << " distinct code roots, " "they need to be in the set, but there are only " << root_set.length(); - size_t num_popped = 0; - for (size_t i = 1; i <= num_to_add; i++) { - bool removed = root_set.remove((nmethod*) i); - if (removed) { - num_popped += 1; - } else { - break; - } - } - ASSERT_EQ(num_popped, num_to_add) - << "Managed to pop " << num_popped << " code roots, but only " - << num_to_add << " were added"; + root_set.clear(); ASSERT_EQ(root_set.length(), 0u) << "should be empty"; } From e13d59ce4b2e7e672d6ff9e717eb397c96b4c423 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 2 Sep 2026 07:05:55 +0000 Subject: [PATCH 190/223] 8391452: C2: Add StressVerifyMeetJoin to CtwRunner Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/type.cpp | 26 +++++++++++++------ src/hotspot/share/opto/typejavaptr.hpp | 26 ++++++++++++++++--- .../src/sun/hotspot/tools/ctw/CtwRunner.java | 1 + 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 7e0ea7d294c3..748c9298c2a0 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3762,6 +3762,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter interfaces->verify_is_loaded(); } assert(instance_id != InstanceTop, "must not have top instance_id"); + assert(xk || instance_id == InstanceBot, "a known instance must have an exact type"); assert(ptr != Constant || instance_id == InstanceBot, "a constant cannot have an instance_id"); #endif if (Compile::current()->eliminate_boxing() && (t == InstPtr) && @@ -3970,10 +3971,16 @@ const Type* TypeOopPtr::xjoin_helper(const Type* t) const { case OopPtr: { const TypeOopPtr* tp = t->is_oopptr(); - int instance_id = join_instance_id(tp->instance_id()); const TypePtr* speculative = xjoin_speculative(tp); int depth = join_inline_depth(tp->inline_depth()); - return make(join_ptr(tp->ptr()), join_offset(tp->offset()), instance_id, speculative, depth); + + Offset offset = join_offset(tp->offset()); + if (offset == Offset::top) { + return TypePtr::make(AnyPtr, TopPTR, offset, speculative, depth); + } + + int instance_id = join_instance_id(tp->instance_id()); + return make(join_ptr(tp->ptr()), offset, instance_id, speculative, depth); } case InstPtr: @@ -5534,9 +5541,10 @@ const Type* TypeMetadataPtr::xjoin(const Type* t) const { switch (t->base()) { case AnyPtr: { const TypePtr* tp = t->is_ptr(); - PTR ptr = join_ptr(tp->ptr()); Offset offset = join_offset(tp->offset()); - switch (tp->ptr()) { + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + switch (other_ptr) { case TopPTR: case Null: return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); @@ -5887,9 +5895,10 @@ const Type* TypeInstKlassPtr::xjoin(const Type* t) const { switch (t->base()) { case AnyPtr: { const TypePtr* tp = t->is_ptr(); - PTR ptr = join_ptr(tp->ptr()); Offset offset = join_offset(tp->offset()); - switch (tp->ptr()) { + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + switch (other_ptr) { case TopPTR: case Null: return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); @@ -6376,9 +6385,10 @@ const Type* TypeAryKlassPtr::xjoin(const Type* t) const { switch (t->base()) { case AnyPtr: { const TypePtr* tp = t->is_ptr(); - PTR ptr = join_ptr(tp->ptr()); Offset offset = join_offset(tp->offset()); - switch (tp->ptr()) { + PTR other_ptr = offset == Offset::top ? TopPTR : tp->ptr(); + PTR ptr = join_ptr(other_ptr); + switch (other_ptr) { case TopPTR: case Null: return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); diff --git a/src/hotspot/share/opto/typejavaptr.hpp b/src/hotspot/share/opto/typejavaptr.hpp index 8c964cd77757..752c4324cae2 100644 --- a/src/hotspot/share/opto/typejavaptr.hpp +++ b/src/hotspot/share/opto/typejavaptr.hpp @@ -63,6 +63,11 @@ class TypeJavaPtrMeetHelper { Type::Offset offset = meet_offset(t1, t2); auto interfaces = meet_interfaces(t1, t2); auto flat_in_array = meet_flat_in_array(t1, t2); + // Due to value renumbering, types with the same instance_id may correspond to different + // allocations. As a result, we may encounter cases when instance_id is not InstanceBot, but + // the result is not an exact type, normalize instance_id to InstanceBot then. This is done in + // the callees of this function because here we do not know whether the types of the operands + // match. int instance_id = meet_instance_id(t1, t2); auto speculative = meet_speculative(t1, t2); int inline_depth = meet_inline_depth(t1, t2); @@ -70,7 +75,7 @@ class TypeJavaPtrMeetHelper { if (base1 != base2) { TypePtr::PTR ptr = t1->ptr() == TypePtr::BotPTR || t2->ptr() == TypePtr::BotPTR ? TypePtr::BotPTR : TypePtr::NotNull; return OopType::InstType::make(ptr, OopType::ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, - flat_in_array, instance_id, speculative, inline_depth); + flat_in_array, TypeOopPtr::InstanceBot, speculative, inline_depth); } else if (base1 == Type::InstPtr) { return instptr_type_xmeet(t1->is_instptr(), t2->is_instptr(), offset, interfaces, flat_in_array, instance_id, speculative, inline_depth); } else { @@ -89,6 +94,10 @@ class TypeJavaPtrMeetHelper { ConstOopType const_oop = nullptr; meet_ptr_and_const_oop(ptr, const_oop, t1, t2); bool xk = t1->klass_is_exact() && t2->klass_is_exact() && k1 == k2; + if (!xk) { + // See oopptr_type_xmeet + instance_id = TypeOopPtr::InstanceBot; + } // Consider an unloaded class to be a direct child of j.l.O and not have any subclass decltype(k1) k; @@ -130,6 +139,11 @@ class TypeJavaPtrMeetHelper { bool xk = t1->klass_is_exact() && t2->klass_is_exact() && !aryptr_klass_disjoint(t1, t2); auto field_offset = t1->field_offset().meet(t2->field_offset()); bool autobox_cache = t1->is_autobox_cache() && t2->is_autobox_cache(); + + if (!xk) { + // See oopptr_type_xmeet + instance_id = TypeOopPtr::InstanceBot; + } return AryOopType::make(ptr, const_oop, ary, klass, xk, offset, field_offset, instance_id, speculative, inline_depth, autobox_cache); } @@ -246,8 +260,13 @@ class TypeJavaPtrMeetHelper { template static TypePtr::PTR meet_ary_klass_ptr(const AryKlassType* t1, const AryKlassType* t2) { + // Sometimes, the klass is computed and cached, sometimes it is not. In general, the only time + // we need to compare klass() is when t1->elem() and t2->elem() are both TypeInt::INT. In other + // cases, it is fine if klass_match == true, other parameters must reveal if t1 and t2 are not + // of the same type. + bool klass_match = t1->klass() == nullptr || t2->klass() == nullptr || t1->klass() == t2->klass(); if (t1->ptr() == TypePtr::Constant && t2->ptr() == TypePtr::Constant && - t1->elem() == t2->elem() && t1->klass() == t2->klass() && + t1->elem() == t2->elem() && klass_match && t1->is_not_flat() == t2->is_not_flat() && t1->is_not_null_free() == t2->is_not_null_free() && t1->is_flat() == t2->is_flat() && t1->is_null_free() == t2->is_null_free() && t1->is_atomic() == t2->is_atomic() && t1->is_refined_type() == t2->is_refined_type()) { @@ -336,7 +355,8 @@ class TypeJavaPtrMeetHelper { if (both_are_exact) { return exact_klass != other_klass || exact_type->interfaces() != other_type->interfaces(); } else { - return !exact_klass->is_subtype_of(other_klass) || !exact_type->interfaces()->contains(other_type->interfaces()); + return !other_klass->is_loaded() || !exact_klass->is_subtype_of(other_klass) || + !exact_type->interfaces()->contains(other_type->interfaces()); } } diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index d9facb130789..6c81db9e0ab8 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -323,6 +323,7 @@ private String[] cmd(long classStart, long classStop) { "-XX:+StressMacroExpansion", "-XX:+StressMacroElimination", "-XX:+StressIncrementalInlining", + "-XX:+StressVerifyMeetJoin", // StressSeed is uint "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE), // Do not fail on huge methods where StressGCM makes register From 64f205e48450264dbb6effcf0c406446cf2a4dc6 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 2 Sep 2026 07:42:18 +0000 Subject: [PATCH 191/223] 8391474: [windows] TimeZone_md.c some RegCloseKey calls on hSubKey are missing Reviewed-by: naoto --- src/java.base/windows/native/libjava/TimeZone_md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java.base/windows/native/libjava/TimeZone_md.c b/src/java.base/windows/native/libjava/TimeZone_md.c index 5adecff50e7c..7b78951793c1 100644 --- a/src/java.base/windows/native/libjava/TimeZone_md.c +++ b/src/java.base/windows/native/libjava/TimeZone_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,6 +327,7 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) if (ret != ERROR_SUCCESS) { goto err; } + RegCloseKey(hSubKey); break; } @@ -363,6 +364,7 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) * found matched record, terminate search */ strcpy(winZoneName, subKeyName); + RegCloseKey(hSubKey); break; } out: From 235c95eaf22e1595186bbc286f334bcf841fd317 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Wed, 2 Sep 2026 07:49:10 +0000 Subject: [PATCH 192/223] 8384192: java/net/httpclient/IdleConnectionTimeoutTest.java fails with AssertionFailedError: idleConnectionTimeoutEvent was not expected but occurred ==> expected: <200> but was: <400> Reviewed-by: dfuchs --- .../jdk/internal/net/http/ConnectionPool.java | 28 +- .../internal/net/http/Http2Connection.java | 50 +++- .../internal/net/http/Http3Connection.java | 53 +++- .../IdleConnectionTimeoutReuseTest.java | 265 ++++++++++++++++++ 4 files changed, 377 insertions(+), 19 deletions(-) create mode 100644 test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index e1725aa92d59..4e6b6b11d761 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -161,12 +161,17 @@ HttpConnection getConnection(boolean secure, InetSocketAddress addr, InetSocketAddress proxy) { if (stopped) return null; + List purgedConnections; + HttpConnection acquiredConnection; stateLock.lock(); try { - return getConnection0(secure, addr, proxy); + purgedConnections = purgeExpiredConnections(timeSource.instant()); + acquiredConnection = getConnection0(secure, addr, proxy); } finally { stateLock.unlock(); } + purgedConnections.forEach(this::close); + return acquiredConnection; } private HttpConnection getConnection0(boolean secure, @@ -319,16 +324,7 @@ long purgeExpiredConnectionsAndReturnNextDeadline(Deadline now) { List closelist; stateLock.lock(); try { - closelist = expiryList.purgeUntil(now); - for (HttpConnection c : closelist) { - if (c instanceof PlainHttpConnection) { - boolean wasPresent = removeFromPool(c, plainPool); - assert wasPresent; - } else { - boolean wasPresent = removeFromPool(c, sslPool); - assert wasPresent; - } - } + closelist = purgeExpiredConnections(now); nextPurge = now.until( expiryList.nextExpiryDeadline().orElse(now), ChronoUnit.MILLIS); @@ -339,6 +335,16 @@ long purgeExpiredConnectionsAndReturnNextDeadline(Deadline now) { return nextPurge; } + private List purgeExpiredConnections(Deadline now) { + assert stateLock.isHeldByCurrentThread(); + var closelist = expiryList.purgeUntil(now); + for (HttpConnection c : closelist) { + var wasPresent = removeFromPool(c, c instanceof PlainHttpConnection ? plainPool : sslPool); + assert wasPresent; + } + return closelist; + } + private void close(HttpConnection c) { try { c.close(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index c113672f8d80..44b81e24c1c4 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -68,6 +68,7 @@ import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.MinimalFuture; import jdk.internal.net.http.common.SequentialScheduler; +import jdk.internal.net.http.common.TimeSource; import jdk.internal.net.http.common.Utils; import jdk.internal.net.http.common.ValidatingHeadersConsumer; import jdk.internal.net.http.common.ValidatingHeadersConsumer.Context; @@ -222,18 +223,35 @@ final class IdleConnectionTimeoutEvent extends TimeoutEvent { */ @Override public void handle() { - // first check if the connection is still idle. - // must be done with the "stateLock" held, to allow for synchronizing actions like - // closing the connection and checking out from connection pool (which too is expected - // to use this same lock) stateLock.lock(); try { + + // Are we still the effective idle timeout handler? If not, we're done. + if (idleConnectionTimeoutEvent != this) { + if (debug.on()) { + debug.log("Idle timeout event is found obsolete, skipping it"); + } + return; + } + if (cancelled) { if (debug.on()) { - debug.log("Idle timeout event already cancelled, not initiating idle connection close"); + debug.log("Idle timeout event is found cancelled, skipping it"); } return; } + + if (!isIdle()) { + if (debug.on()) { + debug.log("Idle timeout event found the connection in-use, skipping the event"); + } + // When the active/reserved stream later closes, it won't + // arm a new idle timer upon seeing this one, which is + // already fired. Hence, detach this event. + idleConnectionTimeoutEvent = null; + return; + } + // the connection has been idle long enough, we now // mark a state indicating that the connection is chosen // for idle termination and should not be handed out (from the pool) @@ -653,12 +671,21 @@ void abandonStream() { final boolean shouldClose() { stateLock.lock(); try { - return finalStream() && streams.isEmpty() && numReservedClientStreams == 0; + return finalStream() && isIdle(); } finally { stateLock.unlock(); } } + private boolean isIdle() { + assert stateLock.isHeldByCurrentThread(); + // There should not be any server reserved streams if there is no client + // streams for HTTP/2, because push promises are supposed to be created + // while the main response stream is still open. Hence, we don't do a + // `numReservedServerStreams == 0` check. + return streams.isEmpty() && numReservedClientStreams == 0; + } + /** * Throws an IOException if h2 was not negotiated */ @@ -1551,6 +1578,17 @@ boolean tryReserveForPoolCheckout() { // must be done with "stateLock" held to co-ordinate idle connection management stateLock.lock(); try { + + // Idle connection timeout processing might be delayed when this + // connection checkout request has arrived. Hence, first check for + // the timeout. + var timedOut = idleConnectionTimeoutEvent != null && + !idleConnectionTimeoutEvent.deadline().isAfter(TimeSource.now()); + if (timedOut && isIdle()) { + setFinalStream(); + return false; + } + cancelIdleCloseEvent(); // consider the reservation successful only if the connection is open and // hasn't been chosen for idle termination diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java index 6bf1b9184f86..024de6bd49b3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java @@ -52,6 +52,7 @@ import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.MinimalFuture; +import jdk.internal.net.http.common.TimeSource; import jdk.internal.net.http.common.Utils; import jdk.internal.net.http.http3.ConnectionSettings; import jdk.internal.net.http.http3.Http3Error; @@ -725,12 +726,17 @@ public String toString() { private boolean finalStreamClosed() { lock(); try { - return this.finalStream && this.exchangeStreams.isEmpty() && this.reservedStreamCount.get() == 0; + return this.finalStream && isIdle(); } finally { unlock(); } } + private boolean isIdle() { + assert lock.isHeldByCurrentThread(); + return exchangeStreams.isEmpty() && reservedStreamCount.get() == 0; + } + /** * Called by the {@link Http3ExchangeImpl} when the exchange is closed. * @@ -894,6 +900,18 @@ boolean tryReserveForPoolCheckout() { // must be done with "stateLock" held to co-ordinate idle connection management lock(); try { + + // Idle connection timeout processing might be delayed when this + // connection checkout request has arrived. Hence, first check for + // the timeout. + var idleConnectionTimeoutEventCopy = idleConnectionTimeoutEvent; + var timedOut = idleConnectionTimeoutEventCopy != null && + !idleConnectionTimeoutEventCopy.deadline().isAfter(TimeSource.now()); + if (timedOut && isIdle()) { + setFinalStream(); + return false; + } + cancelIdleShutdownEvent(); // co-ordinate with the QUIC connection to prevent it from silently terminating // a potentially idle transport @@ -981,9 +999,40 @@ public void handle() { boolean okToIdleTimeout; lock(); try { - if (cancelled || idleShutDownInitiated) { + + // Are we still the effective idle timeout handler? If not, we're done. + if (idleConnectionTimeoutEvent != this) { + if (debug.on()) { + debug.log("Idle timeout event is found obsolete, skipping it"); + } return; } + + if (cancelled) { + if (debug.on()) { + debug.log("Idle timeout event is found cancelled, skipping it"); + } + return; + } + + if (idleShutDownInitiated) { + if (debug.on()) { + debug.log("Idle timeout event found the shutdown initiated, skipping the event"); + } + return; + } + + if (!isIdle()) { + if (debug.on()) { + debug.log("Idle timeout event found the connection in-use, skipping the event"); + } + // When the active/reserved stream later closes, it won't + // arm a new idle timer upon seeing this one, which is + // already fired. Hence, detach this event. + idleConnectionTimeoutEvent = null; + return; + } + idleShutDownInitiated = true; if (debug.on()) { debug.log("H3 idle shutdown initiated"); diff --git a/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java b/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java new file mode 100644 index 000000000000..a99115717c00 --- /dev/null +++ b/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; + +import org.junit.jupiter.api.function.ThrowingSupplier; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import javax.net.ssl.SSLContext; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; +import static java.net.http.HttpClient.Version.HTTP_2; +import static java.net.http.HttpClient.Version.HTTP_3; +import static java.net.http.HttpOption.H3_DISCOVERY; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static java.net.http.HttpResponse.BodyHandlers.discarding; +import static jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange.RSPBODY_EMPTY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +/* + * @test + * @summary Verify that a connection with overdue idle timeout is not reused + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * + * @comment Why do we force the usage of virtual threads at the selector? The + * problem we are stressing is not an issue specific to virtual threads + * or their usage in the HTTP client. We're forcing the usage of + * virtual threads, because this way it is easier to starve the thread + * pool used by the selector. This issue could very well be observed + * using platform threads, but it would be more difficult to reproduce + * reliably. + * + * @comment Why do we skip the test on Windows? On Windows, the selector + * implementation (i.e., `WEPollSelectorImpl`) blocks a virtual thread + * without releasing its carrier. With both + * `jdk.virtualThreadScheduler.{parallelism,maxPoolSize}` set to 1, no + * carrier remains to compensate for the blocked selector, and the + * initial client request cannot make progress. We could increase the + * VT scheduler capacity, but this contradicts with the reason we fix + * it to 1 in the first place: to starve the HTTP Client selector + * threads. + * + * @comment Why do we configure both `{quic,tcp}.selector.useVirtualThreads`? + * As of date, connection eviction is triggered by the selector of + * `HttpClientImpl`, not by the QUIC selector. Being prudent, we fix + * both to virtual threads. + * + * @comment Why are both `parallelism` and `maxPoolSize` 1? Because the default + * carrier thread pool (i.e., FJP) requires `parallelism <= maxPoolSize` + * and having 1 thread in the pool is easier to make it starve. + * + * @requires os.family != "windows" + * + * @run junit/othervm + * -Djdk.httpclient.keepalive.timeout=1 + * -Djdk.internal.httpclient.quic.selector.useVirtualThreads=always + * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=always + * -Djdk.virtualThreadScheduler.parallelism=1 + * -Djdk.virtualThreadScheduler.maxPoolSize=1 + * ${test.main.class} + */ + +class IdleConnectionTimeoutReuseTest { + + /** + * @implNote + * This test has several timing-sensitive assumptions. If these assumptions + * hold, the test will verify the subject behavior. If not, the test will + * and should pass anyway. Therefore, it is not a problem if the assumptions + * don't hold. Local testing has shown that these assumptions do hold almost + * always. + */ + @ParameterizedTest + @EnumSource(InfraFactory.class) + void testDelayedIdleTimeout(InfraFactory infraFactory) throws Throwable { + try (var server = infraFactory.createStartedServer(); + var client = infraFactory.createClient()) { + + // Issue the 1st request establishing the connection + var request = infraFactory.createRequest(server); + var response1 = client.send(request, discarding()); + assertEquals(200, response1.statusCode()); + var response1Label = response1.connectionLabel().orElseThrow(); + + // Give the worker that closes the first exchange time to register the + // idle timer. Note that this is timing-sensitive, and hence, an + // assumption. + Thread.sleep(Utils.adjustTimeout(200)); + + // In the JTreg `@test` configuration above, + // + // 1. Virtual thread pool is configured to have at most 1 carrier thread. + // 2. HTTP client's selector is configured to use virtual threads. + // + // Occupy that single carrier thread to block the HTTP client's selector + // from processing idle timeouts. + var carrierBlockerStarted = new CountDownLatch(1); + var carrierBlockerStopped = new AtomicBoolean(); + var carrierBlocker = Thread.ofVirtual().start(() -> { + carrierBlockerStarted.countDown(); + while (!carrierBlockerStopped.get()) { + Thread.onSpinWait(); + } + }); + carrierBlockerStarted.await(); + + try { + + // The virtual selector cannot process the 1s timeout while its + // only carrier is occupied. Let the timeout become overdue + // before reserving the connection for the 2nd request. + Thread.sleep(Utils.adjustTimeout(1500)); + + // Execute the 2nd request + var response2Future = client.sendAsync(request, discarding()); + + // Release the carrier thread blocker, so both idle timeout + // processing and serving of the 2nd request can proceed. We + // first sleep some to allow the latter to proceed as much as + // possible. This increases its chances to get executed first. + Thread.sleep(Utils.adjustTimeout(100)); + carrierBlockerStopped.set(true); + carrierBlocker.join(); + + // At this stage, we cannot know for certain if idle timeout + // processing or serving of the 2nd request gets executed first. + // If it is the latter, we will be verifying what this test aims + // to stress. In either case, the 2nd request should not be + // served using the timed out connection. + var response2 = response2Future.join(); + assertEquals(200, response2.statusCode()); + assertNotEquals( + response1Label, response2.connectionLabel().orElseThrow(), + "The 1st overdue connection should not have been reused!"); + + } finally { + carrierBlockerStopped.set(true); + carrierBlocker.join(); + } + + } + } + + enum InfraFactory { + + H1C(false, HTTP_1_1), + + H1S(true, HTTP_1_1), + + H2C(false, HTTP_2), + + H2S(true, HTTP_2), + + H3( + true, + HTTP_3, + () -> HttpTestServer.create(HTTP_3_URI_ONLY, SSL_CONTEXT), + requestBuilder -> requestBuilder + .version(HTTP_3) + .setOption(H3_DISCOVERY, HTTP_3_URI_ONLY)); + + private final boolean secure; + + private final Version version; + + private final ThrowingSupplier serverFactory; + + private final Consumer requestBuilderConfigurer; + + private final String handlerPath = "/idle-timeout-" + this; + + InfraFactory(boolean secure, Version version) { + this( + secure, + version, + () -> HttpTestServer.create(version, secure ? SSL_CONTEXT : null), + requestBuilder -> requestBuilder.version(version)); + } + + InfraFactory( + boolean secure, + Version version, + ThrowingSupplier serverFactory, + Consumer requestBuilderConfigurer) { + this.secure = secure; + this.version = version; + this.serverFactory = serverFactory; + this.requestBuilderConfigurer = requestBuilderConfigurer; + } + + private HttpTestServer createStartedServer() throws Throwable { + var server = serverFactory.get(); + server.addHandler(this::send200, handlerPath); + server.start(); + return server; + } + + private void send200(HttpTestExchange exchange) throws IOException { + exchange.sendResponseHeaders(200, RSPBODY_EMPTY); + } + + private HttpRequest createRequest(HttpTestServer server) { + var requestUri = URIBuilder.newBuilder() + .scheme(secure ? "https" : "http") + .host(server.getAddress().getAddress()) + .port(server.getAddress().getPort()) + .path(handlerPath) + .buildUnchecked(); + var requestBuilder = HttpRequest.newBuilder(requestUri); + requestBuilderConfigurer.accept(requestBuilder); + return requestBuilder.build(); + } + + private HttpClient createClient() { + var clientBuilder = HttpServerAdapters.createClientBuilderFor(version) + .proxy(NO_PROXY); + if (secure) { + clientBuilder.sslContext(SSL_CONTEXT); + } + return clientBuilder.build(); + } + + } + + private static final SSLContext SSL_CONTEXT = SimpleSSLContext.findSSLContext(); + +} From c92811804f8c4db057c2680c835d9c55fdacecf9 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 2 Sep 2026 07:54:51 +0000 Subject: [PATCH 193/223] 8391176: Cleanup the markWord locking bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Castañeda Lozano Reviewed-by: rcastanedalo, thartmann, stefank, fbredberg --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 5 - .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 6 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 16 +-- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 - src/hotspot/cpu/arm/macroAssembler_arm.cpp | 4 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 4 +- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 5 - src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 24 ++-- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 2 - .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 5 - .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 6 +- .../cpu/riscv/macroAssembler_riscv.cpp | 13 +- .../cpu/riscv/macroAssembler_riscv.hpp | 1 - src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 5 - src/hotspot/cpu/s390/macroAssembler_s390.cpp | 21 ++- src/hotspot/cpu/s390/macroAssembler_s390.hpp | 1 - src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 5 - src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 6 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 13 +- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 2 - src/hotspot/share/cds/heapShared.cpp | 2 +- .../share/interpreter/interpreterRuntime.cpp | 8 -- src/hotspot/share/oops/markWord.cpp | 6 +- src/hotspot/share/oops/markWord.hpp | 65 +++++----- src/hotspot/share/oops/oop.hpp | 4 - src/hotspot/share/oops/oop.inline.hpp | 8 -- src/hotspot/share/opto/graphKit.cpp | 35 +---- src/hotspot/share/opto/graphKit.hpp | 2 +- src/hotspot/share/opto/loopopts.cpp | 6 +- src/hotspot/share/opto/macro.cpp | 53 +------- src/hotspot/share/opto/macroArrayCopy.cpp | 29 +---- src/hotspot/share/opto/mulnode.cpp | 27 ++-- src/hotspot/share/opto/phaseX.cpp | 10 -- src/hotspot/share/prims/whitebox.cpp | 20 +++ src/hotspot/share/runtime/basicLock.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 1 - src/hotspot/share/runtime/sharedRuntime.cpp | 8 -- src/hotspot/share/runtime/synchronizer.cpp | 57 +++++---- src/hotspot/share/runtime/vframeArray.cpp | 1 - src/hotspot/share/runtime/vmStructs.cpp | 4 +- .../classes/sun/jvm/hotspot/oops/Mark.java | 28 ++-- .../classes/sun/jvm/hotspot/oops/Oop.java | 2 +- .../hotspot/runtime/ObjectSynchronizer.java | 2 +- test/hotspot/gtest/oops/test_markWord.cpp | 27 ++-- .../TestMarkWordLoadIdealization.java | 121 ++++++++++++++++++ .../jtreg/serviceability/sa/ClhsdbAttach.java | 6 +- .../serviceability/sa/ClhsdbLongConstant.java | 8 +- test/lib/jdk/test/whitebox/WhiteBox.java | 5 + 48 files changed, 316 insertions(+), 377 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index d05526890cba..9a35a01c4d2d 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1569,13 +1569,8 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Label test_mark_word; Register tmp = op->tmp()->as_register(); __ ldr(tmp, Address(op->array()->as_register(), oopDesc::mark_offset_in_bytes())); - __ tst(tmp, markWord::unlocked_value); - __ br(Assembler::NE, test_mark_word); - __ load_prototype_header(tmp, op->array()->as_register()); - __ bind(test_mark_word); __ tst(tmp, markWord::null_free_array_bit_in_place); } diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index fba316bf293e..96a4f4d3daaf 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -221,8 +221,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register t1, assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a lea"); // Try to lock. Transition lock-bits 0b01 => 0b00 - orr(t1_mark, t1_mark, markWord::unlocked_value); - eor(t3_t, t1_mark, markWord::unlocked_value); + orr(t1_mark, t1_mark, markWord::lock_neutral_value); + eor(t3_t, t1_mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ t1_mark, /*new*/ t3_t, Assembler::xword, memory_order_acquire); br(Assembler::NE, slow_path); @@ -383,7 +383,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, Register t1, // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); - orr(t3_t, t1_mark, markWord::unlocked_value); + orr(t3_t, t1_mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ t1_mark, /*new*/ t3_t, Assembler::xword, memory_order_release); br(Assembler::EQ, unlocked); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 0dada25f208c..74fd6e0d42af 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5318,12 +5318,6 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi cmpw(tmp1, tmp2); } -void MacroAssembler::load_prototype_header(Register dst, Register src) { - Register tmp = (dst == rscratch1) ? rscratch2 : rscratch1; - load_klass(dst, src, tmp); - ldr(dst, Address(dst, Klass::prototype_header_offset())); -} - void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { // FIXME: Should this be a store release? concurrent gcs assumes // klass length is valid if klass field is not null. @@ -7896,13 +7890,13 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register t1, R // Try to lock. Transition lock bits 0b01 => 0b00 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); - orr(mark, mark, markWord::unlocked_value); + orr(mark, mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { // Mask inline_type bit such that we go to the slow path if object is an inline type andr(mark, mark, ~((int) markWord::inline_type_bit_in_place)); } - eor(t, mark, markWord::unlocked_value); + eor(t, mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ mark, /*new*/ t, Assembler::xword, memory_order_acquire); br(Assembler::NE, slow); @@ -7961,16 +7955,16 @@ void MacroAssembler::fast_unlock(Register obj, Register t1, Register t2, Registe tbnz(mark, log2i_exact(markWord::monitor_value), push_and_slow); #ifdef ASSERT - // Check header not unlocked (0b01). + // Check header not unlocked / lock-neutral (0b01). Label not_unlocked; - tbz(mark, log2i_exact(markWord::unlocked_value), not_unlocked); + tbz(mark, log2i_exact(markWord::lock_neutral_value), not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); #endif // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); - orr(t, mark, markWord::unlocked_value); + orr(t, mark, markWord::lock_neutral_value); cmpxchg(obj, mark, t, Assembler::xword, memory_order_release); br(Assembler::EQ, unlocked); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 13d5c6b8377d..ba46983c7a07 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -999,8 +999,6 @@ class MacroAssembler: public Assembler { // stored using routines that take a jobject. void store_heap_oop_null(Address dst); - void load_prototype_header(Register dst, Register src); - void store_klass_gap(Register dst, Register src); // This dummy is to prevent a call to store_heap_oop from diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index 6715effa68fd..ce79fc57ccd4 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -1780,7 +1780,7 @@ void MacroAssembler::fast_lock(Register obj, Register t1, Register t2, Register Register new_hdr = t2; ldr(new_hdr, Address(obj, oopDesc::mark_offset_in_bytes())); bic(new_hdr, new_hdr, markWord::lock_mask_in_place); // new header (00) - orr(old_hdr, new_hdr, markWord::unlocked_value); // old header (01) + orr(old_hdr, new_hdr, markWord::lock_neutral_value); // old header (01) Label dummy; @@ -1829,7 +1829,7 @@ void MacroAssembler::fast_unlock(Register obj, Register t1, Register t2, Registe Register new_hdr = t2; ldr(old_hdr, Address(obj, oopDesc::mark_offset_in_bytes())); bic(old_hdr, old_hdr, markWord::lock_mask_in_place); // old header (00) - orr(new_hdr, old_hdr, markWord::unlocked_value); // new header (01) + orr(new_hdr, old_hdr, markWord::lock_neutral_value); // new header (01) // Try to swing header from locked to unlocked Label dummy; diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 5779bcc26ac6..ed4d9c8f2e73 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -938,8 +938,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ ldr(Rtemp, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - assert(markWord::unlocked_value == 1, "adjust this code"); - __ tbz(Rtemp, exact_log2(markWord::unlocked_value), slow_case); + assert(markWord::lock_neutral_value == 1, "adjust this code"); + __ tbz(Rtemp, exact_log2(markWord::lock_neutral_value), slow_case); __ bics(Rtemp, Rtemp, ~markWord::hash_mask_in_place); __ mov(R0, AsmOperand(Rtemp, lsr, markWord::hash_shift), ne); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index d6051da562a3..cd9bb80d9507 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -3127,13 +3127,8 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Label test_mark_word; Register tmp = op->tmp()->as_register(); __ ld(tmp, oopDesc::mark_offset_in_bytes(), op->array()->as_register()); - __ andi_(R0, tmp, markWord::unlocked_value); - __ bne(CR0, test_mark_word); - __ load_prototype_header(tmp, op->array()->as_register()); - __ bind(test_mark_word); __ andi(R0, tmp, markWord::null_free_array_bit_in_place); __ cmpwi(BOOL_RESULT, R0, 0); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index e7bf14dad340..c48071291062 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2734,7 +2734,7 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Check for monitor (0b10) or locked (0b00). ld(mark, oopDesc::mark_offset_in_bytes(), obj); andi_(R0, mark, markWord::lock_mask_in_place); - cmpldi(CR0, R0, markWord::unlocked_value); + cmpldi(CR0, R0, markWord::lock_neutral_value); bgt(CR0, inflated); bne(CR0, slow_path); @@ -2913,7 +2913,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe #ifdef ASSERT // Check header not unlocked (0b01). Label not_unlocked; - andi_(t, mark, markWord::unlocked_value); + andi_(t, mark, markWord::lock_neutral_value); beq(CR0, not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); @@ -3374,11 +3374,6 @@ void MacroAssembler::load_metadata(Register dst, Register src) { } } -void MacroAssembler::load_prototype_header(Register dst, Register src) { - load_klass(dst, src); - ld(dst, Klass::prototype_header_offset(), dst); -} - void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); @@ -4838,17 +4833,18 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, } bind(retry); - STATIC_ASSERT(markWord::locked_value == 0); // Or need to change this! + STATIC_ASSERT(markWord::fast_locked_value == 0); // Or need to change this! + STATIC_ASSERT(markWord::lock_neutral_value == 1); // Or need to change this! if (!is_unlock) { ldarx(tmp, obj, MacroAssembler::cmpxchgx_hint_acquire_lock()); - xori(tmp, tmp, markWord::unlocked_value); // flip unlocked bit + xori(tmp, tmp, markWord::lock_neutral_value); // flip lock-neutral bit andi_(R0, tmp, markWord::lock_mask_in_place | markWord::inline_type_bit_in_place); - bne(CR0, failed); // failed if new header doesn't contain locked_value (which is 0) or belongs to an inline type + bne(CR0, failed); // failed if new header doesn't contain fast_locked_value (which is 0) or belongs to an inline type } else { ldarx(tmp, obj, MacroAssembler::cmpxchgx_hint_release_lock()); andi_(R0, tmp, markWord::lock_mask_in_place); - bne(CR0, failed); // failed if old header doesn't contain locked_value (which is 0) - ori(tmp, tmp, markWord::unlocked_value); // set unlocked bit + bne(CR0, failed); // failed if old header doesn't contain fast_locked_value (which is 0) + ori(tmp, tmp, markWord::lock_neutral_value); // set lock-neutral bit } stdcx_(tmp, obj); bne(CR0, retry); @@ -4900,7 +4896,7 @@ void MacroAssembler::fast_lock(Register box, Register obj, Register t1, Register // Check header for monitor (0b10) or locked (0b00). ld(mark, oopDesc::mark_offset_in_bytes(), obj); - xori(t, mark, markWord::unlocked_value); + xori(t, mark, markWord::lock_neutral_value); andi_(t, t, markWord::lock_mask_in_place); bne(CR0, slow); @@ -4974,7 +4970,7 @@ void MacroAssembler::fast_unlock(Register obj, Register t1, Label& slow) { #ifdef ASSERT // Check header not unlocked (0b01). Label not_unlocked; - andi_(t, mark, markWord::unlocked_value); + andi_(t, mark, markWord::lock_neutral_value); beq(CR0, not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 533d03230a4d..839e5dcd69d9 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -846,8 +846,6 @@ class MacroAssembler: public Assembler { void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); - void load_prototype_header(Register dst, Register src); - void inline_layout_info(Register holder_klass, Register index, Register layout_info); // inline type data payload offsets... diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 496e26d3c0b5..b2473a9356e5 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1262,13 +1262,8 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Label test_mark_word; Register tmp = op->tmp()->as_register(); __ ld(tmp, Address(op->array()->as_register(), oopDesc::mark_offset_in_bytes())); - __ test_bit(t0, tmp, exact_log2(markWord::unlocked_value)); - __ bnez(t0, test_mark_word); - __ load_prototype_header(tmp, op->array()->as_register()); - __ bind(test_mark_word); __ test_bit(tmp, tmp, exact_log2(markWord::null_free_array_bit_in_place)); } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index edd018c733f5..c2684982c140 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -123,8 +123,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a la"); // Try to lock. Transition lock-bits 0b01 => 0b00 - ori(tmp1_mark, tmp1_mark, markWord::unlocked_value); - xori(tmp3_t, tmp1_mark, markWord::unlocked_value); + ori(tmp1_mark, tmp1_mark, markWord::lock_neutral_value); + xori(tmp3_t, tmp1_mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ tmp1_mark, /*new*/ tmp3_t, Assembler::int64, /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_t); bne(tmp1_mark, tmp3_t, slow_path); @@ -295,7 +295,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); - ori(tmp3_t, tmp1_mark, markWord::unlocked_value); + ori(tmp3_t, tmp1_mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ tmp1_mark, /*new*/ tmp3_t, Assembler::int64, /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, /*result*/ tmp3_t); beq(tmp1_mark, tmp3_t, unlocked); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index fdb2ee314b37..2f44cf42dc37 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3927,11 +3927,6 @@ void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { decode_klass_not_null(dst, tmp); } -void MacroAssembler::load_prototype_header(Register dst, Register src, Register tmp) { - load_klass(dst, src, tmp); - ld(dst, Address(dst, Klass::prototype_header_offset())); -} - void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { // FIXME: Should this be a store release? concurrent gcs assumes // klass length is valid if klass field is not null. @@ -7137,13 +7132,13 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register tmp1, // Try to lock. Transition lock-bits 0b01 => 0b00 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a la"); - ori(mark, mark, markWord::unlocked_value); + ori(mark, mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { // Mask inline_type bit such that we go to the slow path if object is an inline type andi(mark, mark, ~((int) markWord::inline_type_bit_in_place)); } - xori(t, mark, markWord::unlocked_value); + xori(t, mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ mark, /*new*/ t, Assembler::int64, /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ t); bne(mark, t, slow, /* is_far */ true); @@ -7206,7 +7201,7 @@ void MacroAssembler::fast_unlock(Register obj, Register tmp1, Register tmp2, Reg #ifdef ASSERT // Check header not unlocked (0b01). Label not_unlocked; - test_bit(t, mark, exact_log2(markWord::unlocked_value)); + test_bit(t, mark, exact_log2(markWord::lock_neutral_value)); beqz(t, not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); @@ -7214,7 +7209,7 @@ void MacroAssembler::fast_unlock(Register obj, Register tmp1, Register tmp2, Reg // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); - ori(t, mark, markWord::unlocked_value); + ori(t, mark, markWord::lock_neutral_value); cmpxchg(/*addr*/ obj, /*expected*/ mark, /*new*/ t, Assembler::int64, /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, /*result*/ t); beq(mark, t, unlocked); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 00003c902ef2..be684c5ec908 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -201,7 +201,6 @@ class MacroAssembler: public Assembler { void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); void load_klass(Register dst, Register src, Register tmp = t0); - void load_prototype_header(Register dst, Register src, Register tmp = t0); void load_narrow_klass_compact(Register dst, Register src); void load_narrow_klass(Register dst, Register src); void store_klass(Register dst, Register src, Register tmp = t0); diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index d3c143c97aa8..14e72183e90b 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -3109,13 +3109,8 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Label test_mark_word; Register tmp = op->tmp()->as_register(); __ z_lg(tmp, oopDesc::mark_offset_in_bytes(), op->array()->as_register()); - __ z_tmll(tmp, markWord::unlocked_value); - __ z_brnaz(test_mark_word); - __ load_prototype_header(tmp, op->array()->as_register()); - __ bind(test_mark_word); __ z_tmll(tmp, markWord::null_free_array_bit_in_place); } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index e8971e7630e6..bb4a10a5f80b 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -4236,11 +4236,6 @@ void MacroAssembler::load_metadata(Register dst, Register src) { } } -void MacroAssembler::load_prototype_header(Register dst, Register src) { - load_klass(dst, src); - z_lg(dst, Address(dst, Klass::prototype_header_offset())); -} - void MacroAssembler::store_klass(Register klass, Register dst_oop, Register ck) { assert(!UseCompactObjectHeaders, "Don't use with compact headers"); assert_different_registers(dst_oop, klass, Z_R0); @@ -6377,7 +6372,7 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register temp1 { // Try to lock. Transition lock bits 0b01 => 0b00 const Register locked_obj = top; - z_oill(mark, markWord::unlocked_value); + z_oill(mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { static_assert((uint32_t)markWord::inline_type_bit_in_place <= 0x7FFFFFFF, "inline_type_bit_in_place must fit in low 32 bits for z_nilf"); @@ -6386,7 +6381,7 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register temp1 } z_lgr(locked_obj, mark); // Clear lock-bits from locked_obj (locked state) - z_xilf(locked_obj, markWord::unlocked_value); + z_xilf(locked_obj, markWord::lock_neutral_value); z_csg(mark, locked_obj, mark_offset, obj); branch_optimized(Assembler::bcondNotEqual, slow); } @@ -6458,7 +6453,7 @@ void MacroAssembler::fast_unlock(Register obj, Register temp1, Register temp2, L #ifdef ASSERT // Check header not unlocked (0b01). NearLabel not_unlocked; - z_tmll(mark, markWord::unlocked_value); + z_tmll(mark, markWord::lock_neutral_value); z_braz(not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); @@ -6467,7 +6462,7 @@ void MacroAssembler::fast_unlock(Register obj, Register temp1, Register temp2, L { // Try to unlock. Transition lock bits 0b00 => 0b01 Register unlocked_obj = top; z_lgr(unlocked_obj, mark); - z_oill(unlocked_obj, markWord::unlocked_value); + z_oill(unlocked_obj, markWord::lock_neutral_value); z_csg(mark, unlocked_obj, mark_offset, obj); branch_optimized(Assembler::bcondEqual, unlocked); } @@ -6538,7 +6533,7 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis { // Try to lock. Transition lock bits 0b01 => 0b00 assert(mark_offset == 0, "required to avoid a lea"); const Register locked_obj = top; - z_oill(mark, markWord::unlocked_value); + z_oill(mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { static_assert((uint32_t)markWord::inline_type_bit_in_place <= 0x7FFFFFFF, "inline_type_bit_in_place must fit in low 32 bits for z_nilf"); @@ -6547,7 +6542,7 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis } z_lgr(locked_obj, mark); // Clear lock-bits from locked_obj (locked state) - z_xilf(locked_obj, markWord::unlocked_value); + z_xilf(locked_obj, markWord::lock_neutral_value); z_csg(mark, locked_obj, mark_offset, obj); branch_optimized(Assembler::bcondNotEqual, slow_path); } @@ -6725,7 +6720,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg #ifdef ASSERT // Check header not unlocked (0b01). NearLabel not_unlocked; - z_tmll(mark, markWord::unlocked_value); + z_tmll(mark, markWord::lock_neutral_value); z_braz(not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); @@ -6734,7 +6729,7 @@ void MacroAssembler::compiler_fast_unlock_object(Register obj, Register box, Reg { // Try to unlock. Transition lock bits 0b00 => 0b01 Register unlocked_obj = top; z_lgr(unlocked_obj, mark); - z_oill(unlocked_obj, markWord::unlocked_value); + z_oill(unlocked_obj, markWord::lock_neutral_value); z_csg(mark, unlocked_obj, mark_offset, obj); branch_optimized(Assembler::bcondEqual, unlocked); } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 3fd182144724..2b831d1a49cf 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -863,7 +863,6 @@ class MacroAssembler: public Assembler { void decode_klass_not_null(Register dst); void load_klass(Register klass, Address mem); void load_klass(Register klass, Register src_oop); - void load_prototype_header(Register dst, Register src); void store_klass(Register klass, Register dst_oop, Register ck = noreg); // Klass will get compressed if ck not provided. void store_klass_gap(Register s, Register dst_oop); void load_narrow_klass_compact(Register dst, Register src); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 7437de72bf1c..23a457913e5a 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1575,13 +1575,8 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Label test_mark_word; Register tmp = op->tmp()->as_register(); __ movptr(tmp, Address(op->array()->as_register(), oopDesc::mark_offset_in_bytes())); - __ testl(tmp, markWord::unlocked_value); - __ jccb(Assembler::notZero, test_mark_word); - __ load_prototype_header(tmp, op->array()->as_register(), rscratch1); - __ bind(test_mark_word); __ testl(tmp, markWord::null_free_array_bit_in_place); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index a82067e95769..e69a210117ef 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -313,8 +313,8 @@ void C2_MacroAssembler::fast_lock(Register obj, Register box, Register rax_reg, // Try to lock. Transition lock bits 0b01 => 0b00 movptr(rax_reg, mark); - orptr(rax_reg, markWord::unlocked_value); - andptr(mark, ~(int32_t)markWord::unlocked_value); + orptr(rax_reg, markWord::lock_neutral_value); + andptr(mark, ~(int32_t)markWord::lock_neutral_value); lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::notEqual, slow_path); @@ -511,7 +511,7 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register t, // Try to unlock. Transition lock bits 0b00 => 0b01 movptr(reg_rax, mark); andptr(reg_rax, ~(int32_t)markWord::lock_mask_in_place); - orptr(mark, markWord::unlocked_value); + orptr(mark, markWord::lock_neutral_value); lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::notEqual, push_and_slow_path); jmp(unlocked); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index dd6a6ed51ed4..20ca09968b89 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5582,11 +5582,6 @@ void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { decode_klass_not_null(dst, tmp); } -void MacroAssembler::load_prototype_header(Register dst, Register src, Register tmp) { - load_klass(dst, src, tmp); - movptr(dst, Address(dst, Klass::prototype_header_offset())); -} - void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { assert(!UseCompactObjectHeaders, "not with compact headers"); assert_different_registers(src, tmp); @@ -10626,8 +10621,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register reg_r // Try to lock. Transition lock bits 0b01 => 0b00 movptr(tmp, reg_rax); - andptr(tmp, ~(int32_t)markWord::unlocked_value); - orptr(reg_rax, markWord::unlocked_value); + andptr(tmp, ~(int32_t)markWord::lock_neutral_value); + orptr(reg_rax, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { // Mask inline_type bit such that we go to the slow path if object is an inline type andptr(reg_rax, ~((int) markWord::inline_type_bit_in_place)); @@ -10682,7 +10677,7 @@ void MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register tmp, L #ifdef ASSERT // Check header not unlocked (0b01). Label not_unlocked; - testptr(reg_rax, markWord::unlocked_value); + testptr(reg_rax, markWord::lock_neutral_value); jcc(Assembler::zero, not_unlocked); stop("fast_unlock already unlocked"); bind(not_unlocked); @@ -10690,7 +10685,7 @@ void MacroAssembler::fast_unlock(Register obj, Register reg_rax, Register tmp, L // Try to unlock. Transition lock bits 0b00 => 0b01 movptr(tmp, reg_rax); - orptr(tmp, markWord::unlocked_value); + orptr(tmp, markWord::lock_neutral_value); lock(); cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::equal, unlocked); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 7f424966468e..b7c6b379c022 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -407,8 +407,6 @@ class MacroAssembler: public Assembler { // stored using routines that take a jobject. void store_heap_oop_null(Address dst); - void load_prototype_header(Register dst, Register src, Register tmp); - void store_klass_gap(Register dst, Register src); // This dummy is to prevent a call to store_heap_oop from diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index f94582c8a51f..5402a5f9309d 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -918,7 +918,7 @@ void HeapShared::copy_java_mirror(oop orig_mirror, oop scratch_m) { // For valhalla, the prototype header is the same as markWord::prototype(); scratch_m->set_mark(markWord::prototype().copy_set_hash(src_hash)); } - assert(scratch_m->mark().is_unlocked(), "sanity"); + assert(scratch_m->mark().is_lock_neutral(), "sanity"); DEBUG_ONLY(intptr_t archived_hash = scratch_m->identity_hash()); assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 37368279f5cf..f081d7d0968d 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -798,14 +798,6 @@ JRT_END JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem)) oop obj = elem->obj(); assert(Universe::heap()->is_in(obj), "must be an object"); - // The object could become unlocked through a JNI call, which we have no other checks for. - // Give a fatal message if CheckJNICalls. Otherwise we ignore it. - if (obj->is_unlocked()) { - if (CheckJNICalls) { - fatal("Object has been unlocked by JNI"); - } - return; - } ObjectSynchronizer::exit(obj, elem->lock(), JavaThread::current()); // Free entry. If it is not cleared, the exception handling code will try to unlock the monitor // again at method exit or in the case of an exception. diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 7bd55e064b04..3ce3f5dc7405 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -39,11 +39,11 @@ void markWord::print_on(outputStream* st) const { st->print(" mark("); if (has_monitor()) { // last bits = 10 st->print("has_monitor"); - } else if (is_unlocked()) { // last bits = 01 - st->print("is_unlocked"); + } else if (is_lock_neutral()) { // last bits = 01 + st->print("is_lock_neutral"); } else { // last bits = 00 assert(is_fast_locked(), "should be"); - st->print("is_locked"); + st->print("is_fast_locked"); } if (is_inline_type()) { st->print(" inline_type"); diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index b2bd5d89e502..7cb1e5b57285 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -49,13 +49,13 @@ // ------------------------------- // klass:22 hash:31 valhalla:4 age:4 self-fwd:1 lock:2 // -// - lock bits are used to describe lock states: locked/unlocked/monitor-locked +// - lock bits are used to describe lock states: fast-locked/lock-neutral/inflated // and to indicate that an object has been GC marked / forwarded. // -// [header | 00] locked locked regular object header (fast-locking in use) -// [header | 01] unlocked regular object header -// [header | 10] monitor inflated lock -// [ptr | 11] marked used to mark an object (header is swapped out) +// [header | 00] fast_locked object has been fast-locked +// [header | 01] lock_neutral object has no monitor and is not locked +// [header | 10] monitor object has a monitor (lock state recorded there) +// [ptr | 11] marked used to mark an object (header is swapped out) // // - self-fwd - used by some GCs to indicate in-place forwarding. // @@ -179,17 +179,17 @@ class markWord { static constexpr uintptr_t klass_mask_in_place = klass_mask << klass_shift; #endif - static const uintptr_t locked_value = 0; - static const uintptr_t unlocked_value = 1; + static const uintptr_t fast_locked_value = 0; + static const uintptr_t lock_neutral_value = 1; static const uintptr_t monitor_value = 2; static const uintptr_t marked_value = 3; - static const uintptr_t inline_type_pattern = inline_type_bit_in_place | unlocked_value; - static const uintptr_t inline_type_pattern_mask = inline_type_bit_in_place | lock_mask_in_place; + static const uintptr_t inline_type_pattern = inline_type_bit_in_place; + static const uintptr_t inline_type_pattern_mask = inline_type_bit_in_place; static const uintptr_t no_hash = 0 ; // no hash value assigned static const uintptr_t no_hash_in_place = (uintptr_t)no_hash << hash_shift; - static const uintptr_t no_lock_in_place = unlocked_value; + static const uintptr_t no_lock_in_place = lock_neutral_value; static const uint max_age = age_mask; @@ -197,6 +197,7 @@ class markWord { static markWord zero() { return markWord(uintptr_t(0)); } bool is_inline_type() const { + precond(!is_marked()); #ifdef _LP64 // 64 bit encodings only return (mask_bits(value(), inline_type_pattern_mask) == inline_type_pattern); #else @@ -205,22 +206,16 @@ class markWord { } // lock accessors (note that these assume lock_shift == 0) - bool is_locked() const { - return (mask_bits(value(), lock_mask_in_place) != unlocked_value); - } - bool is_unlocked() const { - return (mask_bits(value(), lock_mask_in_place) == unlocked_value); + STATIC_ASSERT(lock_shift == 0); + + bool is_lock_neutral() const { + return (mask_bits(value(), lock_mask_in_place) == lock_neutral_value); } + bool is_marked() const { return (mask_bits(value(), lock_mask_in_place) == marked_value); } - bool is_neutral() const { // Not locked, or marked - a "clean" neutral state - LP64_ONLY(assert(!is_unlocked() || mask_bits(value(), inline_type_bit_in_place) == 0, - "Inline types should not be used for locking. _value: " PTR_FORMAT, _value)); - return (mask_bits(value(), lock_mask_in_place) == unlocked_value); - } - bool is_forwarded() const { // Returns true for normal forwarded (0b011) and self-forwarded (0b1xx). return mask_bits(value(), lock_mask_in_place | self_fwd_bit_in_place) >= static_cast(marked_value); @@ -228,24 +223,24 @@ class markWord { // Should this header be preserved during GC? bool must_be_preserved() const { - // The reserved bits are only guaranteed to be unset if the mark word is "unlocked" - LP64_ONLY(assert(!is_unlocked() || mask_bits(value(), valhalla_reserved_bit_in_place) == 0, + precond(!is_marked()); + LP64_ONLY(assert(mask_bits(value(), valhalla_reserved_bit_in_place) == 0, "Reserved bits should not be used. _value: " PTR_FORMAT, _value)); - return !is_unlocked() || has_hash(); + return !is_lock_neutral() || has_hash(); } // WARNING: The following routines are used EXCLUSIVELY by // synchronization functions. They are not really gc safe. // They must get updated if markWord layout get changed. - markWord set_unlocked() const { - return markWord(value() | unlocked_value); + markWord set_lock_neutral() const { + return markWord((value() & ~lock_mask_in_place) | lock_neutral_value); } bool is_fast_locked() const { - return (value() & lock_mask_in_place) == locked_value; + return (value() & lock_mask_in_place) == fast_locked_value; } markWord set_fast_locked() const { - // Clear the lock_mask_in_place bits to set locked_value: + // Clear the lock_mask_in_place bits to set fast_locked_value: return markWord(value() & ~lock_mask_in_place); } @@ -259,10 +254,10 @@ class markWord { // used to encode pointers during GC markWord clear_lock_bits() const { return markWord(value() & ~lock_mask_in_place); } - // age operations markWord set_marked() { return markWord((value() & ~lock_mask_in_place) | marked_value); } - markWord set_unmarked() { return markWord((value() & ~lock_mask_in_place) | unlocked_value); } + markWord set_unmarked() { return markWord((value() & ~lock_mask_in_place) | lock_neutral_value); } + // age operations uint age() const { return (uint) mask_bits(value() >> age_shift, age_mask); } markWord set_age(uint v) const { assert((v & ~age_mask) == 0, "shouldn't overflow age field"); @@ -314,26 +309,26 @@ class markWord { // Prototype marks for initialization static markWord prototype() { - return markWord(unlocked_value); + return markWord(lock_neutral_value); } static markWord inline_type_prototype() { NOT_LP64(assert(false, "Should not be called in 32 bit mode")); - return markWord(unlocked_value | inline_type_bit_in_place); + return markWord(lock_neutral_value | inline_type_bit_in_place); } static markWord flat_array_prototype(bool null_free) { NOT_LP64(assert(false, "Should not be called in 32 bit mode")); if (null_free) { - return markWord(unlocked_value | flat_array_bit_in_place | null_free_array_bit_in_place); + return markWord(lock_neutral_value | flat_array_bit_in_place | null_free_array_bit_in_place); } else { - return markWord(unlocked_value | flat_array_bit_in_place); + return markWord(lock_neutral_value | flat_array_bit_in_place); } } static markWord null_free_array_prototype() { NOT_LP64(assert(false, "Should not be called in 32 bit mode")); - return markWord(unlocked_value | null_free_array_bit_in_place); + return markWord(lock_neutral_value | null_free_array_bit_in_place); } // Debugging diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 6675c4f49edf..349c5f5a518f 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -261,10 +261,6 @@ class oopDesc { static void verify_on(outputStream* st, oopDesc* oop_desc); static void verify(oopDesc* oopDesc); - // locking operations - inline bool is_locked() const; - inline bool is_unlocked() const; - // asserts and guarantees static bool is_oop(oop obj); static bool is_oop_or_null(oop obj); diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 04176d04b3da..864fbc5e5e72 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -272,14 +272,6 @@ inline void oopDesc::float_field_put(int offset, jfloat value) { *field_add inline jdouble oopDesc::double_field(int offset) const { return *field_addr(offset); } inline void oopDesc::double_field_put(int offset, jdouble value) { *field_addr(offset) = value; } -bool oopDesc::is_locked() const { - return mark().is_locked(); -} - -bool oopDesc::is_unlocked() const { - return mark().is_unlocked(); -} - bool oopDesc::is_gc_marked() const { return mark().is_marked(); } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 27d7f76e02fa..4d9e3cdbc10d 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3922,41 +3922,10 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro return res; } -Node* GraphKit::mark_word_test(Node* obj, uintptr_t mask_val, bool eq, bool check_lock) { +Node* GraphKit::mark_word_test(Node* obj, uintptr_t mask_val, bool eq) { // Load markword Node* mark_adr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); Node* mark = make_load(nullptr, mark_adr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - if (check_lock && !UseCompactObjectHeaders) { - // COH: Locking does not override the markword with a tagged pointer. We can directly read from the markword. - // Check if obj is locked - Node* locked_bit = MakeConX(markWord::unlocked_value); - locked_bit = _gvn.transform(new AndXNode(locked_bit, mark)); - Node* cmp = _gvn.transform(new CmpXNode(locked_bit, MakeConX(0))); - Node* is_unlocked = _gvn.transform(new BoolNode(cmp, BoolTest::ne)); - IfNode* iff = new IfNode(control(), is_unlocked, PROB_MAX, COUNT_UNKNOWN); - _gvn.transform(iff); - Node* locked_region = new RegionNode(3); - Node* mark_phi = new PhiNode(locked_region, TypeX_X); - - // Unlocked: Use bits from mark word - locked_region->init_req(1, _gvn.transform(new IfTrueNode(iff))); - mark_phi->init_req(1, mark); - - // Locked: Load prototype header from klass - set_control(_gvn.transform(new IfFalseNode(iff))); - // Make loads control dependent to make sure they are only executed if array is locked - Node* klass_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); - Node* proto_adr = basic_plus_adr(top(), klass, in_bytes(Klass::prototype_header_offset())); - Node* proto = _gvn.transform(LoadNode::make(_gvn, control(), C->immutable_memory(), proto_adr, proto_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); - - locked_region->init_req(2, control()); - mark_phi->init_req(2, proto); - set_control(_gvn.transform(locked_region)); - record_for_igvn(locked_region); - - mark = mark_phi; - } // Now check if mark word bits are set Node* mask = MakeConX(mask_val); @@ -3967,7 +3936,7 @@ Node* GraphKit::mark_word_test(Node* obj, uintptr_t mask_val, bool eq, bool chec } Node* GraphKit::inline_type_test(Node* obj, bool is_inline) { - return mark_word_test(obj, markWord::inline_type_pattern, is_inline, /* check_lock = */ false); + return mark_word_test(obj, markWord::inline_type_pattern, is_inline); } Node* GraphKit::flat_array_test(Node* array_or_klass, bool flat) { diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 1c109cb56757..3fbef71c8952 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -844,7 +844,7 @@ class GraphKit : public Phase { bool maybe_larval = false); // Inline types - Node* mark_word_test(Node* obj, uintptr_t mask_val, bool eq, bool check_lock = true); + Node* mark_word_test(Node* obj, uintptr_t mask_val, bool eq); Node* inline_type_test(Node* obj, bool is_inline = true); Node* flat_array_test(Node* array_or_klass, bool flat = true); Node* null_free_array_test(Node* array, bool null_free = true); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 4f1f77ee8470..d81ac3b76368 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1124,9 +1124,9 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { } // We can't use immutable memory for the flat array check because we are loading the mark word which is -// mutable. Although the bits we are interested in are immutable (we check for markWord::unlocked_value), -// we need to use raw memory to not break anti dependency analysis. Below code will attempt to still move -// flat array checks out of loops, mainly to enable loop unswitching. +// mutable. Although the bits we are interested in are immutable, we need to use raw memory to not break +// anti dependency analysis. The code below will attempt to still move flat array checks out of loops, +// mainly to enable loop unswitching. void PhaseIdealLoop::move_flat_array_check_out_of_loop(Node* n) { // Skip checks for more than one array if (n->req() > 3) { diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 06dff588c852..df158c2fcd24 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -3083,11 +3083,6 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { // mark words: // // long mark = array1.mark | array2.mark | ...; -// long locked_bit = markWord::unlocked_value & array1.mark & array2.mark & ...; -// if (locked_bit == 0) { -// // One array is locked, load its prototype header from the klass -// mark = array1.klass.proto | array2.klass.proto | ...; -// } // if ((mark & markWord::flat_array_bit_in_place) == 0) { // ... // } @@ -3113,7 +3108,6 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { if (use_mark_word) { Node* mark = MakeConX(0); - Node* locked_bit = MakeConX(markWord::unlocked_value); Node* mem = check->in(FlatArrayCheckNode::Memory); for (uint i = FlatArrayCheckNode::ArrayOrKlass; i < check->req(); ++i) { Node* ary = check->in(i); @@ -3123,52 +3117,19 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { Node* mark_adr = basic_plus_adr(ary, oopDesc::mark_offset_in_bytes()); Node* mark_load = _igvn.transform(LoadNode::make(_igvn, nullptr, mem, mark_adr, mark_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); mark = _igvn.transform(new OrXNode(mark, mark_load)); - locked_bit = _igvn.transform(new AndXNode(locked_bit, mark_load)); } assert(!mark->is_Con(), "Should have been optimized out"); - Node* cmp = _igvn.transform(new CmpXNode(locked_bit, MakeConX(0))); - Node* is_unlocked = _igvn.transform(new BoolNode(cmp, BoolTest::ne)); - // BoolNode might be shared, replace each if user + // Replace the bool node assert(bol->is_Bool() && bol->as_Bool()->_test._test == BoolTest::ne, "unexpected condition"); - for (DUIterator_Last imin, i = bol->last_outs(imin); i >= imin; --i) { - IfNode* old_iff = bol->last_out(i)->as_If(); - Node* ctrl = old_iff->in(0); - RegionNode* region = new RegionNode(3); - Node* mark_phi = new PhiNode(region, TypeX_X); - - // Check if array is unlocked - IfNode* iff = _igvn.transform(new IfNode(ctrl, is_unlocked, PROB_MAX, COUNT_UNKNOWN))->as_If(); - - // Unlocked: Use bits from mark word - region->init_req(1, _igvn.transform(new IfTrueNode(iff))); - mark_phi->init_req(1, mark); - - // Locked: Load prototype header from klass - ctrl = _igvn.transform(new IfFalseNode(iff)); - Node* proto = MakeConX(0); - for (uint i = FlatArrayCheckNode::ArrayOrKlass; i < check->req(); ++i) { - Node* ary = check->in(i); - // Make loads control dependent to make sure they are only executed if array is locked - Node* klass_adr = basic_plus_adr(ary, oopDesc::klass_offset_in_bytes()); - Node* klass = _igvn.transform(LoadKlassNode::make(_igvn, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); - Node* proto_adr = basic_plus_adr(top(), klass, in_bytes(Klass::prototype_header_offset())); - Node* proto_load = _igvn.transform(LoadNode::make(_igvn, ctrl, C->immutable_memory(), proto_adr, proto_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); - proto = _igvn.transform(new OrXNode(proto, proto_load)); - } - region->init_req(2, ctrl); - mark_phi->init_req(2, proto); - // Check if flat array bits are set - Node* mask = MakeConX(markWord::flat_array_bit_in_place); - Node* masked = _igvn.transform(new AndXNode(_igvn.transform(mark_phi), mask)); - cmp = _igvn.transform(new CmpXNode(masked, MakeConX(0))); - Node* is_not_flat = _igvn.transform(new BoolNode(cmp, BoolTest::eq)); + // Check if flat array bits are set + Node* mask = MakeConX(markWord::flat_array_bit_in_place); + Node* masked = _igvn.transform(new AndXNode(mark, mask)); + Node* cmp = _igvn.transform(new CmpXNode(masked, MakeConX(0))); + Node* is_not_flat = _igvn.transform(new BoolNode(cmp, BoolTest::eq)); + _igvn.replace_node(bol, is_not_flat); - ctrl = _igvn.transform(region); - iff = _igvn.transform(new IfNode(ctrl, is_not_flat, PROB_MAX, COUNT_UNKNOWN))->as_If(); - _igvn.replace_node(old_iff, iff); - } _igvn.replace_node(check, C->top()); } else { // Fall back to layout helper check diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 2e549ca05f9a..72e82972c2b3 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -294,36 +294,13 @@ Node* PhaseMacroExpand::generate_nonpositive_guard(Node** ctrl, Node* index, boo } Node* PhaseMacroExpand::mark_word_test(Node** ctrl, Node* obj, MergeMemNode* mem, uintptr_t mask_val, RegionNode* region) { - // Load markword and check if obj is locked + // Load markword Node* mark = make_load_raw(nullptr, mem->memory_at(Compile::AliasIdxRaw), obj, oopDesc::mark_offset_in_bytes(), TypeX_X, TypeX_X->basic_type()); - Node* locked_bit = MakeConX(markWord::unlocked_value); - locked_bit = transform_later(new AndXNode(locked_bit, mark)); - Node* cmp = transform_later(new CmpXNode(locked_bit, MakeConX(0))); - Node* is_unlocked = transform_later(new BoolNode(cmp, BoolTest::ne)); - IfNode* iff = transform_later(new IfNode(*ctrl, is_unlocked, PROB_MAX, COUNT_UNKNOWN))->as_If(); - Node* locked_region = transform_later(new RegionNode(3)); - Node* mark_phi = transform_later(new PhiNode(locked_region, TypeX_X)); - - // Unlocked: Use bits from mark word - locked_region->init_req(1, transform_later(new IfTrueNode(iff))); - mark_phi->init_req(1, mark); - - // Locked: Load prototype header from klass - *ctrl = transform_later(new IfFalseNode(iff)); - // Make loads control dependent to make sure they are only executed if array is locked - Node* klass_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - Node* klass = transform_later(LoadKlassNode::make(_igvn, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); - Node* proto_adr = basic_plus_adr(top(), klass, in_bytes(Klass::prototype_header_offset())); - Node* proto = transform_later(LoadNode::make(_igvn, *ctrl, C->immutable_memory(), proto_adr, proto_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); - - locked_region->init_req(2, *ctrl); - mark_phi->init_req(2, proto); - *ctrl = locked_region; // Now check if mark word bits are set Node* mask = MakeConX(mask_val); - Node* masked = transform_later(new AndXNode(mark_phi, mask)); - cmp = transform_later(new CmpXNode(masked, mask)); + Node* masked = transform_later(new AndXNode(mark, mask)); + Node* cmp = transform_later(new CmpXNode(masked, mask)); Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq)); return generate_fair_guard(ctrl, bol, region); } diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 8dec62d73b32..305731f3d0c7 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -869,39 +869,30 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Search for GraphKit::mark_word_test patterns and fold the test if the result is statically known - Node* load1 = in(1); - Node* load2 = nullptr; - if (load1->is_Phi() && phase->type(load1)->isa_long()) { - load1 = in(1)->in(1); - load2 = in(1)->in(2); - } - if (load1 != nullptr && load1->is_Load() && phase->type(load1)->isa_long() && - (load2 == nullptr || (load2->is_Load() && phase->type(load2)->isa_long()))) { - const TypePtr* adr_t1 = phase->type(load1->in(MemNode::Address))->isa_ptr(); - const TypePtr* adr_t2 = (load2 != nullptr) ? phase->type(load2->in(MemNode::Address))->isa_ptr() : nullptr; - if (adr_t1 != nullptr && adr_t1->offset() == oopDesc::mark_offset_in_bytes() && - (load2 == nullptr || (adr_t2 != nullptr && adr_t2->offset() == in_bytes(Klass::prototype_header_offset())))) { + if (in1->is_Load() && phase->type(in1)->isa_long()) { + const TypePtr* adr_t = phase->type(in1->in(MemNode::Address))->isa_ptr(); + if (adr_t != nullptr && adr_t->offset() == oopDesc::mark_offset_in_bytes()) { if (mask == markWord::inline_type_pattern) { - if (adr_t1->is_inlinetypeptr()) { + if (adr_t->is_inlinetypeptr()) { set_req_X(1, in(2), phase); return this; - } else if (!adr_t1->can_be_inline_type()) { + } else if (!adr_t->can_be_inline_type()) { set_req_X(1, phase->longcon(0), phase); return this; } } else if (mask == markWord::null_free_array_bit_in_place) { - if (adr_t1->is_null_free()) { + if (adr_t->is_null_free()) { set_req_X(1, in(2), phase); return this; - } else if (adr_t1->is_not_null_free()) { + } else if (adr_t->is_not_null_free()) { set_req_X(1, phase->longcon(0), phase); return this; } } else if (mask == markWord::flat_array_bit_in_place) { - if (adr_t1->is_flat()) { + if (adr_t->is_flat()) { set_req_X(1, in(2), phase); return this; - } else if (adr_t1->is_not_flat()) { + } else if (adr_t->is_not_flat()) { set_req_X(1, phase->longcon(0), phase); return this; } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index d8c59c01f4e3..d1b7b6df62fc 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2537,16 +2537,6 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ } } - // AndLNode::Ideal folds GraphKit::mark_word_test patterns. Give it a chance to run. - if (n->is_Load() && use->is_Phi()) { - for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { - Node* u = use->fast_out(i); - if (u->Opcode() == Op_AndL) { - worklist.push(u); - } - } - } - uint use_op = use->Opcode(); if(use->is_Cmp()) { // Enable CMP/BOOL optimization add_users_to_worklist0(use, worklist); // Put Bool on worklist diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 7e9a97410bca..a4578cf46f03 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2187,6 +2187,22 @@ WB_ENTRY(jobject, WB_printMethods(JNIEnv* env, jobject wb, jstring class_name_pa return result; WB_END +WB_ENTRY(jint, WB_GetMarkWordOffset(JNIEnv* env, jobject o)) + return oopDesc::mark_offset_in_bytes(); +WB_END + +WB_ENTRY(jlong, WB_GetInlineTypePattern(JNIEnv* env, jobject o)) + return markWord::inline_type_pattern; +WB_END + +WB_ENTRY(jlong, WB_GetNullFreeArrayBitInPlace(JNIEnv* env, jobject o)) + return markWord::null_free_array_bit_in_place; +WB_END + +WB_ENTRY(jlong, WB_GetFlatArrayBitInPlace(JNIEnv* env, jobject o)) + return markWord::flat_array_bit_in_place; +WB_END + WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb, jboolean preserve_static_stubs)) VM_ClearICs clear_ics(preserve_static_stubs == JNI_TRUE); VMThread::execute(&clear_ics); @@ -3103,6 +3119,10 @@ static JNINativeMethod methods[] = { {CC"getIndyCPIndex0", CC"(Ljava/lang/Class;I)I", (void*)&WB_getIndyCPIndex}, {CC"printClasses0", CC"(Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_printClasses}, {CC"printMethods0", CC"(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_printMethods}, + {CC"getMarkWordOffset", CC"()I", (void*)&WB_GetMarkWordOffset}, + {CC"getInlineTypePattern", CC"()J", (void*)&WB_GetInlineTypePattern}, + {CC"getNullFreeArrayBitInPlace", CC"()J", (void*)&WB_GetNullFreeArrayBitInPlace}, + {CC"getFlatArrayBitInPlace", CC"()J", (void*)&WB_GetFlatArrayBitInPlace}, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 73f9cc94b0aa..03d576ae5729 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -38,7 +38,7 @@ void BasicLock::print_on(outputStream* st, oop owner) const { void BasicLock::move_to(oop obj, BasicLock* dest) { // Check to see if we need to inflate the lock. This is only needed // if an object is locked using "this" lightweight monitor. In that - // case, the displaced_header() is unlocked/neutral, because the + // case, the displaced_header() is lock-neutral, because the // displaced_header() contains the header for the originally unlocked // object. However the lock could have already been inflated. But it // does not matter, this inflation will just be a no-op. For other cases, diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index ce271e35cdd4..e633d12278b8 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1500,7 +1500,6 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArrayowner()->is_locked(), "object must be locked now"); assert(obj->mark().has_monitor(), "must be"); assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); assert(ObjectSynchronizer::read_monitor(obj())->has_owner(deoptee_thread), "must be"); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0a239388d0e4..e00dd3213e19 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2099,14 +2099,6 @@ void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThrea } } - // The object could become unlocked through a JNI call, which we have no other checks for. - // Give a fatal message if CheckJNICalls. Otherwise we ignore it. - if (obj->is_unlocked()) { - if (CheckJNICalls) { - fatal("Object has been unlocked by JNI"); - } - return; - } ObjectSynchronizer::exit(obj, lock, current); } diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 7a20af676c6d..da60b586b8df 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -704,8 +704,8 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, } } - // Unlocked case, header in place - assert(mark.is_unlocked(), "sanity check"); + // Lock-neutral case + assert(mark.is_lock_neutral(), "sanity check"); return false; } @@ -728,16 +728,12 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob mark = obj->mark_acquire(); if (mark.is_fast_locked()) { - // Some other thread fast_locked + // Some other thread fast-locked the object. return Threads::owning_thread_from_object(t_list, h_obj()); } } - // Unlocked case, header in place - // Cannot have assertion since this object may have been - // locked by another thread when reaching here. - // assert(mark.is_unlocked(), "sanity check"); - + // Lock-neutral case return nullptr; } @@ -1485,7 +1481,7 @@ void ObjectSynchronizer::deflate_mark_word(oop obj) { assert(mark.has_hash(), "obj with inflated monitor must have had a hash"); while (mark.has_monitor()) { - const markWord new_mark = mark.clear_lock_bits().set_unlocked(); + const markWord new_mark = mark.set_lock_neutral(); mark = obj->cas_set_mark(new_mark, mark); } } @@ -1607,14 +1603,14 @@ class ObjectSynchronizer::VerifyThreadState { inline bool ObjectSynchronizer::fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current) { markWord mark = obj->mark(); - while (mark.is_unlocked()) { + while (mark.is_lock_neutral()) { ensure_lock_stack_space(current); assert(!lock_stack.is_full(), "must have made room on the lock stack"); assert(!lock_stack.contains(obj), "thread must not already hold the lock"); // Try to swing into 'fast-locked' state. - markWord locked_mark = mark.set_fast_locked(); + markWord fast_locked_mark = mark.set_fast_locked(); markWord old_mark = mark; - mark = obj->cas_set_mark(locked_mark, old_mark); + mark = obj->cas_set_mark(fast_locked_mark, old_mark); if (old_mark == mark) { // Successfully fast-locked, push object to lock-stack and return. lock_stack.push(obj); @@ -1762,7 +1758,6 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) assert(current == Thread::current(), "must be"); markWord mark = object->mark(); - assert(!mark.is_unlocked(), "must be"); LockStack& lock_stack = current->lock_stack(); if (mark.is_fast_locked()) { @@ -1779,9 +1774,9 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) } while (mark.is_fast_locked()) { - markWord unlocked_mark = mark.set_unlocked(); + markWord lock_neutral_mark = mark.set_lock_neutral(); markWord old_mark = mark; - mark = object->cas_set_mark(unlocked_mark, old_mark); + mark = object->cas_set_mark(lock_neutral_mark, old_mark); if (old_mark == mark) { // CAS successful, remove from lock_stack size_t recursion = lock_stack.remove(object) - 1; @@ -1790,6 +1785,16 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) } } + // The object could become unlocked through a JNI call, which we have no other checks for. + // Give a fatal message if CheckJNICalls. Otherwise we ignore it. + if (mark.is_lock_neutral()) { + if (CheckJNICalls) { + fatal("Object has been unlocked by JNI"); + } + + return; + } + assert(mark.has_monitor(), "must be"); // The monitor exists ObjectMonitor* monitor; @@ -1818,7 +1823,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchro for (;;) { markWord mark = obj->mark_acquire(); - if (mark.is_unlocked()) { + if (mark.is_lock_neutral()) { // No lock, IMSE. THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread is not owner", nullptr); @@ -1866,7 +1871,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_fast_locked_object(oop object, Object (void)object->identity_hash(current); markWord mark = object->mark_acquire(); - assert(!mark.is_unlocked(), "Cannot be unlocked"); + assert(mark.is_fast_locked() || mark.has_monitor(), "Must be fast-locked or async inflated"); for (;;) { // Fetch the monitor from the table @@ -1960,7 +1965,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_and_enter(oop object, BasicLock* lock os::naked_yield(); } else { - assert(mark.is_unlocked(), "Implied"); + assert(mark.is_lock_neutral(), "Implied"); // Retry immediately } @@ -1977,7 +1982,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_and_enter(oop object, BasicLock* lock // the ObjectMonitor owner and remove the // lock from the locking_thread's lock stack. // * fast-locked - Coerce it to inflated from fast-locked. - // * neutral - Inflate the object. Successful CAS is locked + // * lock-neutral - Inflate the object. Successful CAS is locked // CASE: inflated if (mark.has_monitor()) { @@ -2014,18 +2019,16 @@ ObjectMonitor* ObjectSynchronizer::inflate_and_enter(oop object, BasicLock* lock break; // Success } - // CASE: neutral (unlocked) + // CASE: lock-neutral - // Catch if the object's header is not neutral (not locked and - // not marked is what we care about here). - assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); + assert(mark.is_lock_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); markWord old_mark = object->cas_set_mark(mark.set_has_monitor(), mark); if (old_mark != mark) { // CAS failed continue; } - // Transitioned from unlocked to monitor means locking_thread owns the lock. + // Transitioned from lock-neutral to monitor means locking_thread owns the lock. monitor->set_owner_from_anonymous(locking_thread); return monitor; @@ -2089,9 +2092,9 @@ bool ObjectSynchronizer::quick_enter_internal(oop obj, BasicLock* lock, JavaThre return true; } - if (mark.is_unlocked()) { - markWord locked_mark = mark.set_fast_locked(); - if (obj->cas_set_mark(locked_mark, mark) == mark) { + if (mark.is_lock_neutral()) { + markWord fast_locked_mark = mark.set_fast_locked(); + if (obj->cas_set_mark(fast_locked_mark, mark) == mark) { // Successfully fast-locked, push object to lock-stack and return. lock_stack.push(obj); return true; diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 050bfee131b0..66af4db24aab 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -93,7 +93,6 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { dest->set_obj(nullptr); } else { assert(monitor->owner() != nullptr, "monitor owner must not be null"); - assert(!monitor->owner()->is_unlocked(), "monitor must be locked"); dest->set_obj(monitor->owner()); assert(ObjectSynchronizer::current_thread_holds_lock(current_thread, Handle(current_thread, dest->obj())), "should be held, before move_to"); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 3196b6f31ef3..789699368823 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1815,8 +1815,8 @@ declare_constant(markWord::hash_mask) \ declare_constant(markWord::hash_mask_in_place) \ \ - declare_constant(markWord::locked_value) \ - declare_constant(markWord::unlocked_value) \ + declare_constant(markWord::fast_locked_value) \ + declare_constant(markWord::lock_neutral_value) \ declare_constant(markWord::monitor_value) \ declare_constant(markWord::marked_value) \ \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 851ec52abf04..3f217edc9835 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -63,8 +63,8 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc ageMaskInPlace = db.lookupLongConstant("markWord::age_mask_in_place").longValue(); hashMask = db.lookupLongConstant("markWord::hash_mask").longValue(); hashMaskInPlace = db.lookupLongConstant("markWord::hash_mask_in_place").longValue(); - lockedValue = db.lookupLongConstant("markWord::locked_value").longValue(); - unlockedValue = db.lookupLongConstant("markWord::unlocked_value").longValue(); + fastLockedValue = db.lookupLongConstant("markWord::fast_locked_value").longValue(); + neutralValue = db.lookupLongConstant("markWord::lock_neutral_value").longValue(); monitorValue = db.lookupLongConstant("markWord::monitor_value").longValue(); markedValue = db.lookupLongConstant("markWord::marked_value").longValue(); noHash = db.lookupLongConstant("markWord::no_hash").longValue(); @@ -94,8 +94,8 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc private static long hashMask; private static long hashMaskInPlace; - private static long lockedValue; - private static long unlockedValue; + private static long fastLockedValue; + private static long neutralValue; private static long monitorValue; private static long markedValue; @@ -123,11 +123,11 @@ public Address valueAsAddress() { } // lock accessors (note that these assume lock_shift == 0) - public boolean isLocked() { - return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue); + public boolean isNonNeutral() { + return (Bits.maskBitsLong(value(), lockMaskInPlace) != neutralValue); } - public boolean isUnlocked() { - return (Bits.maskBitsLong(value(), lockMaskInPlace) == unlockedValue); + public boolean isNeutral() { + return (Bits.maskBitsLong(value(), lockMaskInPlace) == neutralValue); } public boolean isMarked() { return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue); @@ -141,15 +141,15 @@ public boolean isBeingInflated() { // Should this header be preserved during GC? public boolean mustBePreserved() { - return (!isUnlocked() || !hasNoHash()); + return (isNonNeutral() || !hasNoHash()); } // WARNING: The following routines are used EXCLUSIVELY by // synchronization functions. They are not really gc safe. // They must get updated if markWord layout get changed. - public boolean hasLocker() { - return ((value() & lockMaskInPlace) == lockedValue); + public boolean isFastLocked() { + return ((value() & lockMaskInPlace) == fastLockedValue); } public boolean hasMonitor() { return ((value() & monitorValue) != 0); @@ -168,7 +168,7 @@ public ObjectMonitor monitor() { return null; } public boolean hasDisplacedMarkHelper() { - return ((value() & unlockedValue) == 0); + return ((value() & neutralValue) == 0); } public Mark displacedMarkHelper() { if (Assert.ASSERTS_ENABLED) { @@ -195,13 +195,13 @@ public Klass getKlass() { // Debugging public void printOn(PrintStream tty) { - if (isLocked()) { + if (isNonNeutral()) { tty.print("locked(0x" + Long.toHexString(value()) + ")->"); displacedMarkHelper().printOn(tty); } else { if (Assert.ASSERTS_ENABLED) { - Assert.that(isUnlocked(), "just checking"); + Assert.that(isNeutral(), "just checking"); } tty.print("mark("); tty.print("hash " + Long.toHexString(hash()) + ","); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java index d565a5b0000d..4a42240314a8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java @@ -129,7 +129,7 @@ public boolean equals(Object obj) { /** Identity hash in the target VM */ public long identityHash() { Mark mark = getMark(); - if (mark.isUnlocked() && (!mark.hasNoHash())) { + if (mark.isNeutral() && (!mark.hasNoHash())) { return (int) mark.hash(); } else if (mark.isMarked()) { return (int) mark.hash(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java index 9c2cef7d73b5..35ed66f14f13 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java @@ -51,7 +51,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc public long identityHashValueFor(Oop obj) { Mark mark = obj.getMark(); - if (mark.isUnlocked()) { + if (mark.isNeutral()) { // FIXME: can not generate marks in debugging system return mark.hash(); } else if (mark.hasMonitor()) { diff --git a/test/hotspot/gtest/oops/test_markWord.cpp b/test/hotspot/gtest/oops/test_markWord.cpp index 4e322b53d445..1147d8e3ecd3 100644 --- a/test/hotspot/gtest/oops/test_markWord.cpp +++ b/test/hotspot/gtest/oops/test_markWord.cpp @@ -91,13 +91,13 @@ TEST_VM(markWord, printing) { // Thread tries to lock it. { ObjectLocker ol(h_obj, THREAD); - assert_mark_word_print_pattern(h_obj, "is_locked"); + assert_mark_word_print_pattern(h_obj, "is_fast_locked"); } - assert_mark_word_print_pattern(h_obj, "is_unlocked no_hash"); + assert_mark_word_print_pattern(h_obj, "is_lock_neutral no_hash"); // Hash the object then print it. intx hash = h_obj->identity_hash(); - assert_mark_word_print_pattern(h_obj, "is_unlocked hash=0x"); + assert_mark_word_print_pattern(h_obj, "is_lock_neutral hash=0x"); // Wait gets the lock inflated. { @@ -114,11 +114,11 @@ TEST_VM(markWord, printing) { } } -static void assert_unlocked_state(markWord mark) { +static void assert_lock_neutral_state(markWord mark) { EXPECT_FALSE(mark.is_fast_locked()); EXPECT_FALSE(mark.has_monitor()); - EXPECT_FALSE(mark.is_locked()); - EXPECT_TRUE(mark.is_unlocked()); + EXPECT_FALSE(mark.is_marked()); + EXPECT_TRUE(mark.is_lock_neutral()); } static void assert_copy_set_hash(markWord mark) { @@ -136,8 +136,7 @@ static void assert_type(markWord mark) { TEST_VM(markWord, prototype) { markWord mark = markWord::prototype(); - assert_unlocked_state(mark); - EXPECT_TRUE(mark.is_neutral()); + assert_lock_neutral_state(mark); assert_type(mark); @@ -156,8 +155,7 @@ static void assert_inline_type(markWord mark) { TEST_VM(markWord, inline_type_prototype) { markWord mark = markWord::inline_type_prototype(); - assert_unlocked_state(mark); - // Don't call mark.is_neutral() on value class instances + assert_lock_neutral_state(mark); assert_test_pattern(&mark, " inline_type"); assert_inline_type(mark); @@ -175,8 +173,7 @@ static void assert_flat_array_type(markWord mark) { TEST_VM(markWord, null_free_flat_array_prototype) { markWord mark = markWord::flat_array_prototype(true /* null_free */); - assert_unlocked_state(mark); - EXPECT_TRUE(mark.is_neutral()); + assert_lock_neutral_state(mark); assert_flat_array_type(mark); EXPECT_TRUE(mark.is_null_free_array()); @@ -193,8 +190,7 @@ TEST_VM(markWord, null_free_flat_array_prototype) { TEST_VM(markWord, nullable_flat_array_prototype) { markWord mark = markWord::flat_array_prototype(false /* null_free */); - assert_unlocked_state(mark); - EXPECT_TRUE(mark.is_neutral()); + assert_lock_neutral_state(mark); assert_flat_array_type(mark); EXPECT_FALSE(mark.is_null_free_array()); @@ -217,8 +213,7 @@ static void assert_null_free_array_type(markWord mark) { TEST_VM(markWord, null_free_array_prototype) { markWord mark = markWord::null_free_array_prototype(); - assert_unlocked_state(mark); - EXPECT_TRUE(mark.is_neutral()); + assert_lock_neutral_state(mark); assert_null_free_array_type(mark); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java new file mode 100644 index 000000000000..e5a9e5674329 --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.valhalla.inlinetypes; + +import compiler.lib.ir_framework.*; +import jdk.internal.misc.Unsafe; +import jdk.internal.value.ValueClass; +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; + +/** + * @test + * @summary Test that loads of object markword bits that are know at JIT-compile + * time are constant-folded by C2 idealizations. + * @library /test/lib / + * @requires vm.compiler2.enabled & vm.flagless + * @enablePreview + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.value + * @run driver ${test.main.class} + */ + +public class TestMarkWordLoadIdealization { + + // Wrap these variables into helper class because WhiteBox API needs to be + // initialized by TestFramework first. + static class WB { + static final long MARK_WORD_OFFSET = WhiteBox.getWhiteBox().getMarkWordOffset(); + static final long INLINE_TYPE_PATTERN = WhiteBox.getWhiteBox().getInlineTypePattern(); + static final long NULL_FREE_ARRAY_BIT_IN_PLACE = WhiteBox.getWhiteBox().getNullFreeArrayBitInPlace(); + static final long FLAT_ARRAY_BIT_IN_PLACE = WhiteBox.getWhiteBox().getFlatArrayBitInPlace(); + } + + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + static final Object IDENTITY_OBJECT = new Object(); + static final Integer VALUE_OBJECT = Integer.valueOf(42); + + static final String[] IDENTITY_OBJECT_ARRAY = new String[1]; + static final Integer[] VALUE_OBJECT_ARRAY = new Integer[1]; + static final Integer[] VALUE_OBJECT_ARRAY_NULL_RESTRICTED = + (Integer[]) ValueClass.newNullRestrictedNonAtomicArray(Integer.class, 2, Integer.valueOf(0)); + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", + "--enable-preview"); + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testInlineTypePatternBitLoadNegativeIdealization() { + return (UNSAFE.getLong(IDENTITY_OBJECT, WB.MARK_WORD_OFFSET) & WB.INLINE_TYPE_PATTERN) != 0L; + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testInlineTypePatternBitLoadPositiveIdealization() { + return (UNSAFE.getLong(VALUE_OBJECT, WB.MARK_WORD_OFFSET) & WB.INLINE_TYPE_PATTERN) != 0L; + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testNullFreeArrayBitLoadNegativeIdealization() { + return (UNSAFE.getLong(VALUE_OBJECT_ARRAY, WB.MARK_WORD_OFFSET) & WB.NULL_FREE_ARRAY_BIT_IN_PLACE) != 0L; + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testNullFreeArrayBitLoadPositiveIdealization() { + return (UNSAFE.getLong(VALUE_OBJECT_ARRAY_NULL_RESTRICTED, WB.MARK_WORD_OFFSET) & WB.NULL_FREE_ARRAY_BIT_IN_PLACE) != 0L; + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testFlatArrayBitLoadNegativeIdealization() { + return (UNSAFE.getLong(IDENTITY_OBJECT_ARRAY, WB.MARK_WORD_OFFSET) & WB.FLAT_ARRAY_BIT_IN_PLACE) != 0L; + } + + @Test + @IR(failOn = IRNode.LOAD_L) + public static boolean testFlatArrayBitLoadPositiveIdealization() { + return (UNSAFE.getLong(VALUE_OBJECT_ARRAY, WB.MARK_WORD_OFFSET) & WB.FLAT_ARRAY_BIT_IN_PLACE) != 0L; + } + + @Run(test = {"testInlineTypePatternBitLoadNegativeIdealization", + "testInlineTypePatternBitLoadPositiveIdealization", + "testNullFreeArrayBitLoadNegativeIdealization", + "testNullFreeArrayBitLoadPositiveIdealization", + "testFlatArrayBitLoadNegativeIdealization", + "testFlatArrayBitLoadPositiveIdealization"}) + void run() { + Asserts.assertFalse(testInlineTypePatternBitLoadNegativeIdealization()); + Asserts.assertTrue(testInlineTypePatternBitLoadPositiveIdealization()); + Asserts.assertFalse(testNullFreeArrayBitLoadNegativeIdealization()); + Asserts.assertTrue(testNullFreeArrayBitLoadPositiveIdealization()); + Asserts.assertFalse(testFlatArrayBitLoadNegativeIdealization()); + Asserts.assertTrue(testFlatArrayBitLoadPositiveIdealization()); + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbAttach.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbAttach.java index 6493a803e90f..ac5986714f78 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbAttach.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbAttach.java @@ -58,7 +58,7 @@ public static void main(String[] args) throws Exception { "detach", "universe", "reattach", - "longConstant markWord::locked_value"); + "longConstant markWord::fast_locked_value"); Map> expStrMap = new HashMap<>(); expStrMap.put("where", List.of( @@ -67,8 +67,8 @@ public static void main(String[] args) throws Exception { "MaxJavaStackTraceDepth = ")); expStrMap.put("universe", List.of( "Command not valid until attached to a VM")); - expStrMap.put("longConstant markWord::locked_value", List.of( - "longConstant markWord::locked_value")); + expStrMap.put("longConstant markWord::fast_locked_value", List.of( + "longConstant markWord::fast_locked_value")); test.run(-1, cmds, expStrMap, null); } catch (SkippedException se) { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java index d6f957d4a3a0..9705c9574d3d 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbLongConstant.java @@ -53,18 +53,18 @@ public static void main(String[] args) throws Exception { List cmds = List.of( "longConstant", - "longConstant markWord::locked_value", + "longConstant markWord::fast_locked_value", "longConstant markWord::lock_bits", "longConstant jtreg::test 6", "longConstant jtreg::test"); Map> expStrMap = new HashMap<>(); expStrMap.put("longConstant", List.of( - "longConstant markWord::locked_value", + "longConstant markWord::fast_locked_value", "longConstant markWord::lock_bits", "InvocationCounter::count_increment")); - expStrMap.put("longConstant markWord::locked_value", List.of( - "longConstant markWord::locked_value")); + expStrMap.put("longConstant markWord::fast_locked_value", List.of( + "longConstant markWord::fast_locked_value")); expStrMap.put("longConstant markWord::lock_bits", List.of( "longConstant markWord::lock_bits")); expStrMap.put("longConstant jtreg::test", List.of( diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 7aec78ee6013..88acdc10d548 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -222,6 +222,11 @@ public String printMethods(String classNamePattern, String methodPattern return printMethods0(classNamePattern, methodPattern, flags); } + public native int getMarkWordOffset(); + public native long getInlineTypePattern(); + public native long getNullFreeArrayBitInPlace(); + public native long getFlatArrayBitInPlace(); + // JVMTI private native void addToBootstrapClassLoaderSearch0(String segment); public void addToBootstrapClassLoaderSearch(String segment){ From cd355a6031d39df46098c0219a6e7c04bf12956a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 2 Sep 2026 08:26:28 +0000 Subject: [PATCH 194/223] 8391522: G1: Double counting of embedded member in G1CodeRootSetHashTable::mem_size() Reviewed-by: jsjolen, iwalulya, aboldtch --- src/hotspot/share/gc/g1/g1CodeRootSet.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp index 75e9b1d2b71b..771ab1a7fa2a 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp @@ -237,7 +237,9 @@ class G1CodeRootSetHashTable : public CHeapObj { _table_scanner.set(&_table, BucketClaimSize); } - size_t mem_size() { return sizeof(*this) + _table.get_mem_size(Thread::current()); } + size_t mem_size() { + return sizeof(*this) - sizeof(_table) + _table.get_mem_size(Thread::current()); + } size_t number_of_entries() const { return _num_entries.load_relaxed(); } }; From 6da8ba2dcce62f7518d2aa24bdcfa38e371b52df Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 2 Sep 2026 08:38:15 +0000 Subject: [PATCH 195/223] 8391350: G1: Rename G1HeapRegionRemset::code_roots_list* methods Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 8 ++++---- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 2 +- src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 4 ++-- src/hotspot/share/gc/g1/g1ReviseNumYoungRegionsTask.cpp | 2 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index aee62a5ff68b..a9a76eee634f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -396,7 +396,7 @@ bool G1HeapRegion::verify_code_roots(VerifyOption vo) const { } G1HeapRegionRemSet* hrrs = rem_set(); - size_t code_roots_length = hrrs->code_roots_list_length(); + size_t code_roots_length = hrrs->code_roots_length(); // if this region is empty then there should be no entries // on its code root list diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 69f55228af54..2552df58b3a3 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -88,11 +88,11 @@ class G1HeapRegionRemSet : public CHeapObj { } bool is_empty() const { - return (code_roots_list_length() == 0) && card_set_is_empty(); + return (code_roots_length() == 0) && card_set_is_empty(); } bool occupancy_less_or_equal_than(size_t occ) const { - return (code_roots_list_length() == 0) && card_set()->occupancy_less_or_equal_to(occ); + return (code_roots_length() == 0) && card_set()->occupancy_less_or_equal_to(occ); } // Iterate the cards in this remembered set for merging them into the card table. @@ -177,13 +177,13 @@ class G1HeapRegionRemSet : public CHeapObj { void clean_code_roots(G1HeapRegion* hr); // Returns the number of elements in _code_roots - size_t code_roots_list_length() const { + size_t code_roots_length() const { return _code_roots.length(); } // Returns true if the code roots contains the given // nmethod. - bool code_roots_list_contains(nmethod* nm) { + bool code_roots_contains(nmethod* nm) { return _code_roots.contains(nm); } diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index da8953f5a7df..b477138873a7 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -115,7 +115,7 @@ class G1VerifyCodeRootOopClosure: public OopClosure { G1HeapRegionRemSet* hrrs = hr->rem_set(); // Verify that the code root list for this region // contains the nmethod - if (!hrrs->code_roots_list_contains(_nm)) { + if (!hrrs->code_roots_contains(_nm)) { log_error(gc, verify)("Code root location " PTR_FORMAT " " "from nmethod " PTR_FORMAT " not in strong " "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")", diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 55bc3dccd54f..66dd3967e387 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1184,7 +1184,7 @@ double G1Policy::predict_merge_scan_time(size_t card_rs_length) const { } double G1Policy::predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const { - size_t code_root_length = hr->rem_set()->code_roots_list_length(); + size_t code_root_length = hr->rem_set()->code_roots_length(); return _analytics->predict_code_root_scan_time_ms(code_root_length, for_young_only_phase); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 1c0e15757cc3..00682df647d2 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -269,7 +269,7 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { _max_code_root_mem_sz = code_root_mem_sz; _max_code_root_mem_sz_region = r; } - size_t code_root_elems = hrrs->code_roots_list_length(); + size_t code_root_elems = hrrs->code_roots_length(); G1PerRegionTypeRemSetCounters* current = nullptr; if (r->is_free()) { @@ -392,7 +392,7 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), byte_size_in_proper_unit(max_code_root_rem_set->code_roots_mem_size()), proper_unit_for_byte_size(max_code_root_rem_set->code_roots_mem_size()), - max_code_root_rem_set->code_roots_list_length()); + max_code_root_rem_set->code_roots_length()); } }; diff --git a/src/hotspot/share/gc/g1/g1ReviseNumYoungRegionsTask.cpp b/src/hotspot/share/gc/g1/g1ReviseNumYoungRegionsTask.cpp index 71c8d7bf772c..22cee3bb457f 100644 --- a/src/hotspot/share/gc/g1/g1ReviseNumYoungRegionsTask.cpp +++ b/src/hotspot/share/gc/g1/g1ReviseNumYoungRegionsTask.cpp @@ -55,7 +55,7 @@ class G1ReviseNumYoungRegionsTask::RemSetSamplingClosure : public G1HeapRegionCl bool do_heap_region(G1HeapRegion* r) override { G1HeapRegionRemSet* rem_set = r->rem_set(); - _sampled_code_root_rs_length += rem_set->code_roots_list_length(); + _sampled_code_root_rs_length += rem_set->code_roots_length(); return false; } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 359ed4586c17..f8137a162016 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -436,7 +436,7 @@ class G1PrepareEvacuationTask : public WorkerTask { cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), hr->rem_set()->occupied(), - hr->rem_set()->code_roots_list_length(), + hr->rem_set()->code_roots_length(), _g1h->concurrent_mark()->mark_bitmap()->is_marked(hr->bottom()), hr->pinned_count(), _g1h->is_humongous_reclaim_candidate(index), From 1babfcc2064abb89ba967f1b5d08690ce0c538de Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 2 Sep 2026 10:04:08 +0000 Subject: [PATCH 196/223] 8391476: [Valhalla] PPC64 C1 stubs Load/StoreFlattenedArrayStub require sign extend to pass the index Reviewed-by: dbriemann, amitkumar --- src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index f86b0a9d4fc9..74a8e17dd700 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -155,6 +155,7 @@ LoadFlattenedArrayStub::LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); + __ extsw(_index->as_register(), _index->as_register()); // see CCallingConventionRequiresIntsAsLongs // Pass arguments on stack. __ std(_array->as_register(), -16, R1_SP); __ std(_index->as_register(), -8, R1_SP); @@ -182,6 +183,7 @@ StoreFlattenedArrayStub::StoreFlattenedArrayStub(LIR_Opr array, LIR_Opr index, L void StoreFlattenedArrayStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); + __ extsw(_index->as_register(), _index->as_register()); // see CCallingConventionRequiresIntsAsLongs // Pass arguments on stack. __ std(_array->as_register(), -24, R1_SP); __ std(_index->as_register(), -16, R1_SP); From 934277704d59da73de87efac053c0df37e0d93ca Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 2 Sep 2026 10:48:25 +0000 Subject: [PATCH 197/223] 8391574: (fs) Files.createTempFile should reject prefix with root component (win) Reviewed-by: djelinski --- .../classes/java/nio/file/TempFileHelper.java | 4 +- .../java/nio/file/Files/TemporaryFiles.java | 399 +++++++++++++----- 2 files changed, 298 insertions(+), 105 deletions(-) diff --git a/src/java.base/share/classes/java/nio/file/TempFileHelper.java b/src/java.base/share/classes/java/nio/file/TempFileHelper.java index e5ba85fcf364..b9be8ed243a7 100644 --- a/src/java.base/share/classes/java/nio/file/TempFileHelper.java +++ b/src/java.base/share/classes/java/nio/file/TempFileHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ private static Path generatePath(String prefix, String suffix, Path dir) { String s = prefix + Long.toUnsignedString(n) + suffix; Path name = dir.getFileSystem().getPath(s); // the generated name should be a simple file name - if (name.getParent() != null) + if (name.getParent() != null || name.getRoot() != null) throw new IllegalArgumentException("Invalid prefix or suffix"); return dir.resolve(name); } diff --git a/test/jdk/java/nio/file/Files/TemporaryFiles.java b/test/jdk/java/nio/file/Files/TemporaryFiles.java index 4e971bc54276..fe37c32b4ee1 100644 --- a/test/jdk/java/nio/file/Files/TemporaryFiles.java +++ b/test/jdk/java/nio/file/Files/TemporaryFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,95 +22,150 @@ */ /* @test - * @bug 4313887 6838333 7006126 7023034 + * @bug 4313887 6838333 7006126 7023034 8391574 * @summary Unit test for Files.createTempXXX - * @library .. + * @run junit ${test.main.class} */ -import java.nio.file.*; -import static java.nio.file.StandardOpenOption.*; -import java.nio.file.attribute.*; import java.io.IOException; + +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import static java.nio.file.StandardOpenOption.*; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; + +class TemporaryFiles { + + // system-wide tmp dir + static final Path SYS_TMPDIR = Path.of(System.getProperty("java.io.tmpdir")); + + // local test tmp dir + static Path TEST_TMPDIR; + + @BeforeAll + static void setup() throws Exception { + TEST_TMPDIR = Files.createTempDirectory(Path.of("."), "adir"); + } -public class TemporaryFiles { + @AfterAll + static void cleanup() throws Exception { + Files.delete(TEST_TMPDIR); + } - static void checkInDirectory(Path file, Path dir) { - if (dir == null) - dir = Paths.get(System.getProperty("java.io.tmpdir")); - if (!file.getParent().equals(dir)) - throw new RuntimeException("Not in expected directory"); + /** + * Returns directory, prefix, and suffix combinations for temporary file tests. + */ + static Stream tempFiles() { + return Stream.of( + Arguments.arguments(null, null, null), + Arguments.arguments(null, "blah", null), + Arguments.arguments(null, "", null), + Arguments.arguments(null, null, ".dat"), + Arguments.arguments(null, null, ""), + Arguments.arguments(null, "blah", ".dat"), + Arguments.arguments(TEST_TMPDIR, null, null), + Arguments.arguments(TEST_TMPDIR, "blah", null), + Arguments.arguments(TEST_TMPDIR, "", null), + Arguments.arguments(TEST_TMPDIR, null, ".dat"), + Arguments.arguments(TEST_TMPDIR, null, ""), + Arguments.arguments(TEST_TMPDIR, "blah", ".dat") + ); } - static void testTempFile(String prefix, String suffix, Path dir) - throws IOException - { + @ParameterizedTest + @MethodSource("tempFiles") + void testTempFile(Path dir, String prefix, String suffix) throws Exception { Path file = (dir == null) ? Files.createTempFile(prefix, suffix) : Files.createTempFile(dir, prefix, suffix); try { // check file name String name = file.getFileName().toString(); - if (prefix != null && !name.startsWith(prefix)) - throw new RuntimeException("Should start with " + prefix); - if (suffix == null && !name.endsWith(".tmp")) - throw new RuntimeException("Should end with .tmp"); - if (suffix != null && !name.endsWith(suffix)) - throw new RuntimeException("Should end with " + suffix); + if (prefix != null && !prefix.isEmpty()) { + assertTrue(name.startsWith(prefix), "Should start with " + prefix); + } + if (suffix == null || !suffix.isEmpty()) { + String expectedSuffix = (suffix != null) ? suffix : ".tmp"; + assertTrue(name.endsWith(expectedSuffix), "Should end with " + expectedSuffix); + } // check file is in expected directory - checkInDirectory(file, dir); + Path expectedDir = (dir != null) ? dir : SYS_TMPDIR; + assertEquals(expectedDir, file.getParent(), "Not in expected directory"); - // check that file can be opened for reading and writing + // check file can be opened for reading and writing Files.newByteChannel(file, READ).close(); Files.newByteChannel(file, WRITE).close(); - Files.newByteChannel(file, READ,WRITE).close(); + Files.newByteChannel(file, READ, WRITE).close(); // check file permissions are 0600 or more secure if (Files.getFileStore(file).supportsFileAttributeView("posix")) { Set perms = Files.getPosixFilePermissions(file); perms.remove(PosixFilePermission.OWNER_READ); perms.remove(PosixFilePermission.OWNER_WRITE); - if (!perms.isEmpty()) - throw new RuntimeException("Temporary file is not secure"); + assertTrue(perms.isEmpty(), "Temporary file is not secure"); } } finally { Files.delete(file); } } - static void testTempFile(String prefix, String suffix) - throws IOException - { - testTempFile(prefix, suffix, null); + /** + * Returns directory and prefix combinations for temporary directory tests. + */ + static Stream tempDirectories() { + return Stream.of( + Arguments.arguments(null, null), + Arguments.arguments(null, "blah"), + Arguments.arguments(null, ""), + Arguments.arguments(TEST_TMPDIR, null), + Arguments.arguments(TEST_TMPDIR, "blah"), + Arguments.arguments(TEST_TMPDIR, "") + ); } - static void testTempDirectory(String prefix, Path dir) throws IOException { + @ParameterizedTest + @MethodSource("tempDirectories") + void testTempDirectory(Path dir, String prefix) throws Exception { Path subdir = (dir == null) ? Files.createTempDirectory(prefix) : Files.createTempDirectory(dir, prefix); try { - // check file name - String name = subdir.getFileName().toString(); - if (prefix != null && !name.startsWith(prefix)) - throw new RuntimeException("Should start with " + prefix); + // check directory name + if (prefix != null && !prefix.isEmpty()) { + String name = subdir.getFileName().toString(); + assertTrue(name.startsWith(prefix), "Should start with " + prefix); + } // check directory is in expected directory - checkInDirectory(subdir, dir); + Path expectedDir = (dir != null) ? dir : SYS_TMPDIR; + assertEquals(expectedDir, subdir.getParent(), "Not in expected directory"); - // check directory is empty - DirectoryStream stream = Files.newDirectoryStream(subdir); - try { - if (stream.iterator().hasNext()) - throw new RuntimeException("Tempory directory not empty"); - } finally { - stream.close(); + // check directory is readable (and empty) + try (DirectoryStream stream = Files.newDirectoryStream(subdir)) { + assertFalse(stream.iterator().hasNext(), "Temporary directory not empty"); } - // check that we can create file in directory + // check directory is writable Path file = Files.createFile(subdir.resolve("foo")); try { - Files.newByteChannel(file, READ,WRITE).close(); + Files.newByteChannel(file, READ, WRITE).close(); } finally { Files.delete(file); } @@ -121,77 +176,215 @@ static void testTempDirectory(String prefix, Path dir) throws IOException { perms.remove(PosixFilePermission.OWNER_READ); perms.remove(PosixFilePermission.OWNER_WRITE); perms.remove(PosixFilePermission.OWNER_EXECUTE); - if (!perms.isEmpty()) - throw new RuntimeException("Temporary directory is not secure"); + assertTrue(perms.isEmpty(), "Temporary directory is not secure"); } } finally { Files.delete(subdir); } } - static void testTempDirectory(String prefix) throws IOException { - testTempDirectory(prefix, null); + /** + * Returns file permissions to restrict perissions of temporay file/directory. + */ + static Stream permissions() { + return Stream.of( + "---------", + "r--------", + "-w-------", + "--x------", + "rwx------", + "---r-----", + "----w----", + "-----x---", + "---rwx---", + "------r--", + "-------w-", + "--------x", + "------rwx", + "r--r-----", + "r--r--r--", + "rw-rw----", + "rwxrwx---", + "rw-rw-r--", + "r-xr-x---", + "r-xr-xr-x", + "rwxrwxrwx" + ); } - static void testInvalidFileTemp(String prefix, String suffix) throws IOException { - try { - Path file = Files.createTempFile(prefix, suffix); - Files.delete(file); - throw new RuntimeException("IllegalArgumentException expected"); - } catch (IllegalArgumentException expected) { } + /** + * Checks that the actual permissions are not less secure than the requested. + */ + void checkSecure(Set requested, Set actual) { + assertTrue(actual.stream().allMatch(requested::contains), () -> + "Actual permissions: " + PosixFilePermissions.toString(actual) + + ", requested: " + PosixFilePermissions.toString(requested) + + " - file is less secure than requested"); } - public static void main(String[] args) throws IOException { - // temporary-file directory - testTempFile("blah", ".dat"); - testTempFile("blah", null); - testTempFile(null, ".dat"); - testTempFile(null, null); - testTempDirectory("blah"); - testTempDirectory(null); + @ParameterizedTest + @MethodSource("permissions") + @DisabledOnOs(OS.WINDOWS) + void testPosixAttributes(String permsAsString) throws Exception { + Set perms = PosixFilePermissions.fromString(permsAsString); + FileAttribute> attr = PosixFilePermissions.asFileAttribute(perms); - // a given directory - Path dir = Files.createTempDirectory("tmpdir"); - try { - testTempFile("blah", ".dat", dir); - testTempFile("blah", null, dir); - testTempFile(null, ".dat", dir); - testTempFile(null, null, dir); - testTempDirectory("blah", dir); - testTempDirectory(null, dir); - } finally { - Files.delete(dir); + if (Files.getFileStore(SYS_TMPDIR).supportsFileAttributeView("posix")) { + Path file = Files.createTempFile("blah", ".tmp", attr); + try { + checkSecure(perms, Files.getPosixFilePermissions(file)); + } finally { + Files.delete(file); + } + Path dir = Files.createTempDirectory("blah", attr); + try { + checkSecure(perms, Files.getPosixFilePermissions(dir)); + } finally { + Files.delete(dir); + } + } + + if (Files.getFileStore(TEST_TMPDIR).supportsFileAttributeView("posix")) { + Path file = Files.createTempFile(TEST_TMPDIR, "blah", ".tmp", attr); + try { + checkSecure(perms, Files.getPosixFilePermissions(file)); + } finally { + Files.delete(file); + } + Path dir = Files.createTempDirectory(TEST_TMPDIR, "blah", attr); + try { + checkSecure(perms, Files.getPosixFilePermissions(dir)); + } finally { + Files.delete(dir); + } } + } - // invalid prefix and suffix - testInvalidFileTemp("../blah", null); - testInvalidFileTemp("dir/blah", null); - testInvalidFileTemp("blah", ".dat/foo"); + /** + * Test Files.createTempXXX with an attribute that cannot be set. + */ + @Test + void testUnknownAttribute() { + var attr = new FileAttribute() { + @Override public String name() { return "unknown"; } + @Override public String value() { return "foo"; } + }; + assertThrows(UnsupportedOperationException.class, () -> Files.createTempFile("blah", ".dat", attr)); + assertThrows(UnsupportedOperationException.class, () -> Files.createTempDirectory("blah", attr)); + } - // nulls - try { - Files.createTempFile("blah", ".tmp", (FileAttribute[])null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.createTempFile("blah", ".tmp", new FileAttribute[] { null }); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.createTempDirectory("blah", (FileAttribute[])null); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.createTempDirectory("blah", new FileAttribute[] { null }); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.createTempFile((Path)null, "blah", ".tmp"); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } - try { - Files.createTempDirectory((Path)null, "blah"); - throw new RuntimeException("NullPointerException expected"); - } catch (NullPointerException ignore) { } + /** + * Test Files.createTempXXX with a directory that does not exist. + */ + @Test + void testDirDoesNotExist() { + Path dir = Path.of("DoesNotExist"); + assertTrue(Files.notExists(dir)); + assertThrows(IOException.class, () -> Files.createTempFile(dir, null, null)); + assertThrows(IOException.class, () -> Files.createTempFile(dir, "blah", null)); + assertThrows(IOException.class, () -> Files.createTempFile(dir, null, ".dat")); + assertThrows(IOException.class, () -> Files.createTempFile(dir, "blah", ".dat")); + assertThrows(IOException.class, () -> Files.createTempDirectory(dir, null)); + assertThrows(IOException.class, () -> Files.createTempDirectory(dir, "blah")); + } + + /** + * Returns prefixes that should be rejected. + */ + static Stream badPrefixes() { + return Stream.of( + "/blah", + "../blah", + "dir/blah", + "foo\0bar" + ); + } + + @ParameterizedTest + @MethodSource("badPrefixes") + void testBadPrefix(String prefix) { + Path dir = Path.of("."); + assertThrows(IllegalArgumentException.class, () -> Files.createTempFile(prefix, null)); + assertThrows(IllegalArgumentException.class, () -> Files.createTempFile(dir, prefix, null)); + assertThrows(IllegalArgumentException.class, () -> Files.createTempDirectory(prefix)); + assertThrows(IllegalArgumentException.class, () -> Files.createTempDirectory(dir, prefix)); + } + + /** + * Returns prefixes that should be rejected on Windows. + */ + static Stream badWindowsPrefixes() { + return Stream.of( + "\\\\server", + "\\\\server\\share", + "\\\\?\\UNC\\server\\share", + "C:\\temp\\blah", + "C:temp\\blah", + "C:blah" + ); + } + + /** + * Tests prefixes that should be rejected on Windows. + */ + @ParameterizedTest + @MethodSource("badWindowsPrefixes") + @EnabledOnOs(OS.WINDOWS) + void testBadWindowsPrefixes(String prefix) { + testBadPrefix(prefix); + } + + /** + * Returns suffixes that should be rejected. + */ + static Stream badSuffixes() { + return Stream.of( + ".dat/foo", + "foo\0bar" + ); + } + + @ParameterizedTest + @MethodSource("badSuffixes") + void testBadSuffix(String suffix) { + Path dir = Path.of("."); + assertThrows(IllegalArgumentException.class, () -> Files.createTempFile("blah", suffix)); + assertThrows(IllegalArgumentException.class, () -> Files.createTempFile(dir, "blah", suffix)); + } + + /** + * Returns suffixes that should be rejected on Windows. + */ + static Stream badWindowsSuffixes() { + return Stream.of( + ".dat\\foo", + ":" + ); + } + + @ParameterizedTest + @MethodSource("badWindowsSuffixes") + @EnabledOnOs(OS.WINDOWS) + void testBadWindowsSuffix(String suffix) { + testBadSuffix(suffix); + } + + /** + * Test nulls. + */ + @Test + void testNulls() { + assertThrows(NullPointerException.class, + () -> Files.createTempFile("blah", ".tmp", (FileAttribute[]) null)); + assertThrows(NullPointerException.class, + () -> Files.createTempFile("blah", ".tmp", new FileAttribute[] { null })); + assertThrows(NullPointerException.class, + () -> Files.createTempDirectory("blah", (FileAttribute[]) null)); + assertThrows(NullPointerException.class, + () -> Files.createTempDirectory("blah", new FileAttribute[] { null })); + assertThrows(NullPointerException.class, + () -> Files.createTempFile((Path)null, "blah", ".tmp")); + assertThrows(NullPointerException.class, + () -> Files.createTempDirectory((Path)null, "blah")); } } From 9a9052a8d35381de223eb27455f5b73a4dfdfc5d Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Wed, 2 Sep 2026 11:22:30 +0000 Subject: [PATCH 198/223] 8389108: RISC-V: Use shift pairs for logical right shift and mask patterns Co-authored-by: gns Reviewed-by: dzhang, fyang --- src/hotspot/cpu/riscv/riscv.ad | 104 +++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index e87a11523c5c..f8b9acd18a90 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2850,6 +2850,19 @@ operand immIpowerOf2() %{ interface(CONST_INTER); %} +// Int immediate: the mask of a bitfield extract, i.e. contiguous low-order +// ones, whose width is log2i_exact(mask + 1), e.g. 0xfff, 0xffff, 0x7fffffff. +// Masks that fit into a 12-bit immediate are excluded: a shift followed by +// andi is already as short as the shift pair used to extract the field. +operand immI_bitmask() %{ + predicate(is_power_of_2((juint)n->get_int() + 1) && + !Assembler::is_simm12((int64_t)n->get_int())); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Long Immediate: low 16-bit mask operand immL_16bits() %{ @@ -2870,6 +2883,17 @@ operand immL_32bits() interface(CONST_INTER); %} +// Long immediate: the mask of a bitfield extract, see immI_bitmask above, +// e.g. 0xfff, 0xffffffff, 0x7fffffffffffffff. +operand immL_bitmask() %{ + predicate(is_power_of_2((julong)n->get_long() + 1) && + !Assembler::is_simm12(n->get_long())); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 64 bit unit decrement operand immL_M1() %{ @@ -7264,6 +7288,86 @@ instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ ins_pipe(ialu_reg_shift); %} +// Unsigned bitfield extract: (src >>> rshift) & (2^width - 1) +instruct bitfieldExtractI(iRegINoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ + match(Set dst (AndI (URShiftI src rshift) mask)); + // The field must not extend past the high end of the int. + predicate(log2i_exact((juint)n->in(2)->get_int() + 1) + (n->in(1)->in(2)->get_int() & 0x1f) <= 32); + + ins_cost(ALU_COST * 2); + format %{ "slli $dst, $src, 64 - (($rshift & 0x1f) + width($mask))\n\t" + "srli $dst, $dst, 64 - width($mask)\t#@bitfieldExtractI" %} + + ins_encode %{ + int rshift = $rshift$$constant & 0x1f; + int width = log2i_exact((juint)$mask$$constant + 1); + __ slli(as_Register($dst$$reg), as_Register($src$$reg), 64 - (rshift + width)); + __ srli(as_Register($dst$$reg), as_Register($dst$$reg), 64 - width); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Unsigned bitfield extract from an int with a zero-extending conversion to long. +instruct bitfieldExtractI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ + match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask))); + predicate(log2i_exact((juint)n->in(1)->in(2)->get_int() + 1) + + (n->in(1)->in(1)->in(2)->get_int() & 0x1f) <= 32); + + ins_cost(ALU_COST * 2); + format %{ "slli $dst, $src, 64 - (($rshift & 0x1f) + width($mask))\n\t" + "srli $dst, $dst, 64 - width($mask)\t#@bitfieldExtractI2L" %} + + ins_encode %{ + int rshift = $rshift$$constant & 0x1f; + int width = log2i_exact((juint)$mask$$constant + 1); + __ slli(as_Register($dst$$reg), as_Register($src$$reg), 64 - (rshift + width)); + __ srli(as_Register($dst$$reg), as_Register($dst$$reg), 64 - width); + %} + + ins_pipe(ialu_reg_shift); +%} + +instruct bitfieldExtractL(iRegLNoSp dst, iRegL src, immI rshift, immL_bitmask mask) %{ + match(Set dst (AndL (URShiftL src rshift) mask)); + // The field must not extend past the high end of the long. + predicate(log2i_exact((julong)n->in(2)->get_long() + 1) + (n->in(1)->in(2)->get_int() & 0x3f) <= 64); + + ins_cost(ALU_COST * 2); + format %{ "slli $dst, $src, 64 - (($rshift & 0x3f) + width($mask))\n\t" + "srli $dst, $dst, 64 - width($mask)\t#@bitfieldExtractL" %} + + ins_encode %{ + int rshift = $rshift$$constant & 0x3f; + int width = log2i_exact((julong)$mask$$constant + 1); + __ slli(as_Register($dst$$reg), as_Register($src$$reg), 64 - (rshift + width)); + __ srli(as_Register($dst$$reg), as_Register($dst$$reg), 64 - width); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Extract an int sized field out of a long. The mask is at most 31 bits wide, +// so the zero extended result is a valid int. This is the shape emitted by +// LibraryCallKit::inline_native_hashcode. +instruct bitfieldExtractL2I(iRegINoSp dst, iRegL src, immI rshift, immI_bitmask mask) %{ + match(Set dst (AndI (ConvL2I (URShiftL src rshift)) mask)); + predicate(log2i_exact((juint)n->in(2)->get_int() + 1) + (n->in(1)->in(1)->in(2)->get_int() & 0x3f) <= 64); + + ins_cost(ALU_COST * 2); + format %{ "slli $dst, $src, 64 - (($rshift & 0x3f) + width($mask))\n\t" + "srli $dst, $dst, 64 - width($mask)\t#@bitfieldExtractL2I" %} + + ins_encode %{ + int rshift = $rshift$$constant & 0x3f; + int width = log2i_exact((juint)$mask$$constant + 1); + __ slli(as_Register($dst$$reg), as_Register($src$$reg), 64 - (rshift + width)); + __ srli(as_Register($dst$$reg), as_Register($dst$$reg), 64 - width); + %} + + ins_pipe(ialu_reg_shift); +%} + // Shift Right Arithmetic Register // Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct rShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ From 78567abd11578227402966f0959c5e0e895161da Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 2 Sep 2026 11:45:37 +0000 Subject: [PATCH 199/223] 8376668: Consolidate common logic in FieldLayoutBuilder field sorting methods Reviewed-by: fparain, coleenp --- .../share/classfile/fieldLayoutBuilder.cpp | 160 +++++++----------- .../share/classfile/fieldLayoutBuilder.hpp | 1 + 2 files changed, 61 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 4a3ec7b680ff..49cc3ea337b1 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -841,6 +841,64 @@ void FieldLayoutBuilder::prologue() { _root_group = new FieldGroup(); } +int FieldLayoutBuilder::add_field_to_group(FieldInfo fieldinfo, int idx, FieldGroup* group) { + BasicType type = Signature::basic_type(fieldinfo.signature(_constant_pool)); + switch(type) { + case T_BYTE: + case T_CHAR: + case T_DOUBLE: + case T_FLOAT: + case T_INT: + case T_LONG: + case T_SHORT: + case T_BOOLEAN: + group->add_primitive_field(idx, type); + return type2aelembytes(type); // alignment == size for primitive types + case T_OBJECT: + case T_ARRAY: + { + const bool is_inline_class = _is_inline_type || _is_abstract_value; + // Atomic flat fields can always be used in identity classes. + // Use them only for inline classes if the container is itself atomic. + const bool use_atomic_flat = !is_inline_class || _must_be_atomic; + LayoutKind lk = field_layout_selection(fieldinfo, _inline_layout_info_array, use_atomic_flat); + lk = adjust_with_budget(fieldinfo, _inline_layout_info_array, lk, _flattening_budget); + if (field_is_inlineable(fieldinfo, lk, _inline_layout_info_array)) { + _has_inlineable_fields = true; + } + + if (lk == LayoutKind::REFERENCE) { + if (group != _static_fields) { + _nonstatic_oopmap_count++; + } + group->add_oop_field(idx); + return type2aelembytes(type); // alignment == size for oops + } + + assert(group != _static_fields, "Static fields are not flattened"); + assert(lk != LayoutKind::BUFFERED && lk != LayoutKind::UNKNOWN, + "Invalid layout kind for flat field: %s", LayoutKindHelper::layout_kind_as_string(lk)); + + const int field_index = (int)fieldinfo.index(); + assert(_inline_layout_info_array != nullptr, "Array must have been created"); + assert(_inline_layout_info_array->adr_at(field_index)->klass() != nullptr, "Klass must have been set"); + _has_inlined_fields = true; + InlineKlass* vk = _inline_layout_info_array->adr_at(field_index)->klass(); + if (is_inline_class && !vk->is_naturally_atomic(LayoutKindHelper::is_null_free_flat(lk))) { + _has_non_naturally_atomic_fields = true; + } + group->add_flat_field(idx, vk, lk); + _inline_layout_info_array->adr_at(field_index)->set_kind(lk); + _nonstatic_oopmap_count += vk->nonstatic_oop_map_count(); + _field_info->adr_at(idx)->field_flags_addr()->update_flat(true); + _field_info->adr_at(idx)->set_layout_kind(lk); + return vk->layout_alignment(lk); + } + default: + fatal("Unexpected BasicType"); + } +} + // Field sorting for regular (non-inline) classes: // - fields are sorted in static and non-static fields // - non-static fields are also sorted according to their contention group @@ -869,52 +927,7 @@ void FieldLayoutBuilder::regular_field_sorting() { } } assert(group != nullptr, "invariant"); - BasicType type = Signature::basic_type(fieldinfo.signature(_constant_pool)); - switch(type) { - case T_BYTE: - case T_CHAR: - case T_DOUBLE: - case T_FLOAT: - case T_INT: - case T_LONG: - case T_SHORT: - case T_BOOLEAN: - group->add_primitive_field(idx, type); - break; - case T_OBJECT: - case T_ARRAY: - { - LayoutKind lk = field_layout_selection(fieldinfo, _inline_layout_info_array, true); - lk = adjust_with_budget(fieldinfo, _inline_layout_info_array, lk, _flattening_budget); - if (field_is_inlineable(fieldinfo, lk, _inline_layout_info_array)) { - _has_inlineable_fields = true; - } - - if (lk == LayoutKind::REFERENCE) { - if (group != _static_fields) _nonstatic_oopmap_count++; - group->add_oop_field(idx); - } else { - assert(group != _static_fields, "Static fields are not flattened"); - assert(lk != LayoutKind::BUFFERED && lk != LayoutKind::UNKNOWN, - "Invalid layout kind for flat field: %s", LayoutKindHelper::layout_kind_as_string(lk)); - - const int field_index = (int)fieldinfo.index(); - assert(_inline_layout_info_array != nullptr, "Array must have been created"); - assert(_inline_layout_info_array->adr_at(field_index)->klass() != nullptr, "Klass must have been set"); - _has_inlined_fields = true; - InlineKlass* vk = _inline_layout_info_array->adr_at(field_index)->klass(); - group->add_flat_field(idx, vk, lk); - _inline_layout_info_array->adr_at(field_index)->set_kind(lk); - _nonstatic_oopmap_count += vk->nonstatic_oop_map_count(); - _field_info->adr_at(idx)->field_flags_addr()->update_flat(true); - _field_info->adr_at(idx)->set_layout_kind(lk); - // no need to update _must_be_atomic if vk->must_be_atomic() is true because current class is not an inline class - } - break; - } - default: - fatal("Something wrong?"); - } + add_field_to_group(fieldinfo, idx, group); } _root_group->sort_by_size(); _static_fields->sort_by_size(); @@ -952,60 +965,7 @@ void FieldLayoutBuilder::inline_class_field_sorting() { group = _root_group; } assert(group != nullptr, "invariant"); - BasicType type = Signature::basic_type(fieldinfo.signature(_constant_pool)); - switch(type) { - case T_BYTE: - case T_CHAR: - case T_DOUBLE: - case T_FLOAT: - case T_INT: - case T_LONG: - case T_SHORT: - case T_BOOLEAN: - if (group != _static_fields) { - field_alignment = type2aelembytes(type); // alignment == size for primitive types - } - group->add_primitive_field(idx, type); - break; - case T_OBJECT: - case T_ARRAY: - { - bool use_atomic_flat = _must_be_atomic; // flatten atomic fields only if the container is itself atomic - LayoutKind lk = field_layout_selection(fieldinfo, _inline_layout_info_array, use_atomic_flat); - lk = adjust_with_budget(fieldinfo, _inline_layout_info_array, lk, _flattening_budget); - if (field_is_inlineable(fieldinfo, lk, _inline_layout_info_array)) { - _has_inlineable_fields = true; - } - - if (lk == LayoutKind::REFERENCE) { - if (group != _static_fields) { - _nonstatic_oopmap_count++; - field_alignment = type2aelembytes(type); // alignment == size for oops - } - group->add_oop_field(idx); - } else { - assert(group != _static_fields, "Static fields are not flattened"); - assert(lk != LayoutKind::BUFFERED && lk != LayoutKind::UNKNOWN, - "Invalid layout kind for flat field: %s", LayoutKindHelper::layout_kind_as_string(lk)); - - const int field_index = (int)fieldinfo.index(); - assert(_inline_layout_info_array != nullptr, "Array must have been created"); - assert(_inline_layout_info_array->adr_at(field_index)->klass() != nullptr, "Klass must have been set"); - _has_inlined_fields = true; - InlineKlass* vk = _inline_layout_info_array->adr_at(field_index)->klass(); - if (!vk->is_naturally_atomic(LayoutKindHelper::is_null_free_flat(lk))) _has_non_naturally_atomic_fields = true; - group->add_flat_field(idx, vk, lk); - _inline_layout_info_array->adr_at(field_index)->set_kind(lk); - _nonstatic_oopmap_count += vk->nonstatic_oop_map_count(); - field_alignment = vk->layout_alignment(lk); - _field_info->adr_at(idx)->field_flags_addr()->update_flat(true); - _field_info->adr_at(idx)->set_layout_kind(lk); - } - break; - } - default: - fatal("Unexpected BasicType"); - } + field_alignment = add_field_to_group(fieldinfo, idx, group); if (!fieldinfo.access_flags().is_static() && field_alignment > alignment) alignment = field_alignment; } _root_group->sort_by_size(); diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index 38a44e431d0d..ad148e8441d3 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -341,6 +341,7 @@ class FieldLayoutBuilder : public ResourceObj { protected: void prologue(); void epilogue(); + int add_field_to_group(FieldInfo fieldinfo, int idx, FieldGroup* group); void regular_field_sorting(); void inline_class_field_sorting(); void add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_map, InlineKlass* vk, int offset); From 8555bf5bb12bb1a6b33f4fd470069de5b7841072 Mon Sep 17 00:00:00 2001 From: Ozan Cetin Date: Wed, 2 Sep 2026 11:48:52 +0000 Subject: [PATCH 200/223] 8376286: VM asserts with "assert(false) failed: Possible safepoint reached by thread that does not allow it" when running with -XX:+ExitOnFullCodeCache Reviewed-by: thartmann, kvn --- src/hotspot/share/compiler/compileBroker.cpp | 8 +- .../codecache/ExitOnFullCodeCacheTest.java | 89 +++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 7ca7b57b43b7..3f1b5722f8fa 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2169,8 +2169,12 @@ void CompileBroker::handle_full_code_cache(CodeBlobType code_blob_type) { #ifndef PRODUCT if (ExitOnFullCodeCache) { codecache_print(/* detailed= */ true); - before_exit(JavaThread::current()); - exit_globals(); // will delete tty + // handle_full_code_cache() can be called from a compiler thread while it + // is installing an nmethod, i.e. from a no-safepoint scope. before_exit() + // and exit_globals() acquire safepoint-checking locks (e.g. BeforeExit_lock) + // and would assert "Possible safepoint reached by thread that does not + // allow it". vm_direct_exit() terminates the VM without taking any such + // lock, which is sufficient for this diagnostic develop flag. vm_direct_exit(1); } #endif diff --git a/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java b/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java new file mode 100644 index 000000000000..c8074bd05ca9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java @@ -0,0 +1,89 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8376286 + * @summary With -XX:+ExitOnFullCodeCache the VM must terminate cleanly when the + * code cache fills up, instead of asserting "Possible safepoint reached + * by thread that does not allow it" when the exit is initiated from a + * compiler thread while it is installing an nmethod. + * @requires vm.debug == true & vm.compMode != "Xint" + * @comment ExitOnFullCodeCache is a develop flag, so it is only available in a + * debug VM. The assertion it used to trigger only exists in debug too. + * @library /test/lib + * @run driver compiler.codecache.ExitOnFullCodeCacheTest + */ + +package compiler.codecache; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ExitOnFullCodeCacheTest { + + // Assertion message that used to be triggered by JDK-8376286. + private static final String SAFEPOINT_ASSERT = + "Possible safepoint reached by thread that does not allow it"; + + // Non-method code heap size, in KB. It must be large enough to hold all of + // the VM-internal (non-method) code, and large enough that the reserved + // code cache is big enough for compilation to start (smaller values were + // observed not to overflow the code cache at startup at all). + private static final long NON_NMETHOD_KB = 512000; // 500 MB + + // Margin left for the profiled + non-profiled (+ hot) nmethod heaps, in KB. + // Each of those heaps must be at least the platform minimum, which equals + // the largest allocation/page granularity across supported platforms + // (64 KB). With up to three such heaps, 3 * 64 KB = 192 KB is the minimum; + // 256 KB (a multiple of 64 KB) keeps the code heap sizes valid on 4K/16K/64K + // granularity platforms while still leaving the nmethod heaps small enough + // (~128 KB) that the very first nmethod installation on a compiler thread + // fails and triggers the ExitOnFullCodeCache path while the thread is inside + // nmethod::new_nmethod (a no-safepoint region). Before the fix this asserted. + private static final long NMETHOD_HEAPS_MARGIN_KB = 256; + + public static void main(String[] args) throws Exception { + long reservedKB = NON_NMETHOD_KB + NMETHOD_HEAPS_MARGIN_KB; + + OutputAnalyzer oa = ProcessTools.executeLimitedTestJava( + "-Xcomp", + "-XX:+ExitOnFullCodeCache", + "-XX:NonNMethodCodeHeapSize=" + NON_NMETHOD_KB + "K", + "-XX:ReservedCodeCacheSize=" + reservedKB + "K", + "-version"); + + // The invariant that must always hold, on every platform, is that the + // exit initiated from the compiler thread does not reach the assertion. + oa.shouldNotContain(SAFEPOINT_ASSERT); + oa.shouldNotContain("A fatal error has been detected"); + + // Guard against a silent no-op: if the chosen sizes are not valid on + // this platform's granularity, the VM aborts during initialization + // (e.g. "Invalid code heap sizes") without ever exercising the exit + // path, which would make the test pass without testing anything. Fail + // loudly in that case instead. + oa.shouldNotContain("Invalid code heap sizes"); + oa.shouldNotContain("Error occurred during initialization of VM"); + } +} From 4a02985e9bbf4f5a9974fa815a2e181273fe5918 Mon Sep 17 00:00:00 2001 From: Varada M Date: Wed, 2 Sep 2026 11:56:15 +0000 Subject: [PATCH 201/223] 8390778: [PPC] : stubgen stubs using incorrect StubCodeMark constructor Reviewed-by: adinn, amitkumar --- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 1470ea931b67..2d51119bcc9f 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -580,7 +580,8 @@ class StubGenerator: public StubCodeGenerator { // // address generate_ghash_processBlocks() { - StubCodeMark mark(this, "StubRoutines", "ghash"); + StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + StubCodeMark mark(this, stub_id); address start = __ function_entry(); // Registers for parameters @@ -3839,7 +3840,8 @@ class StubGenerator: public StubCodeGenerator { address generate_floatToFloat16() { __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "floatToFloat16"); + StubId stub_id = StubId::stubgen_f2hf_id; + StubCodeMark mark(this, stub_id); address start = __ function_entry(); __ f2hf(R3_RET, F1_ARG1, F0); __ blr(); @@ -3848,7 +3850,8 @@ class StubGenerator: public StubCodeGenerator { address generate_float16ToFloat() { __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "float16ToFloat"); + StubId stub_id = StubId::stubgen_hf2f_id; + StubCodeMark mark(this, stub_id); address start = __ function_entry(); __ hf2f(F1_RET, R3_ARG1); __ blr(); From dfa989e549bde770d7b2350c50e2007bf4b7649e Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 2 Sep 2026 12:04:13 +0000 Subject: [PATCH 202/223] 8391477: G1: CSet candidate groups selected for optional collection are not sorted Co-authored-by: Thomas Schatzl Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 5 +++++ .../share/gc/g1/g1CollectionSetCandidates.cpp | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index a64b22177205..efe8fe916591 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -388,6 +388,11 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { if (candidates()->retained_groups().num_regions() > 0) { select_candidates_from_retained(time_remaining_ms); } + // Optional groups are selected separately from marking and retained candidate + // lists; sort the combined list to maintain the GC efficiency ordering. + _optional_groups.sort_by_efficiency(); + _optional_groups.verify(); + candidates()->verify(); } else { log_debug(gc, ergo, cset)("No candidates to reclaim."); diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 8b4acaa81e9d..84af28726a48 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -128,16 +128,24 @@ double G1CSetCandidateGroup::predict_group_total_time_ms() const { } int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2) { - double gc_eff1 = (*gr1)->gc_efficiency(); - double gc_eff2 = (*gr2)->gc_efficiency(); + G1CSetCandidateGroup* group_1 = *gr1; + G1CSetCandidateGroup* group_2 = *gr2; + double gc_eff1 = group_1->gc_efficiency(); + double gc_eff2 = group_2->gc_efficiency(); if (gc_eff1 > gc_eff2) { return -1; } else if (gc_eff1 < gc_eff2) { return 1; - } else { - return 0; } + + // Make ordering deterministic by breaking ties with group ids. + if (group_1->group_id() < group_2->group_id()) { + return -1; + } else if (group_1->group_id() > group_2->group_id()) { + return 1; + } + return 0; } G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { } From 9c6e2f495a408b09e076ca05b3c7612d9ac29f21 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 2 Sep 2026 12:23:05 +0000 Subject: [PATCH 203/223] 8391338: [IR Framework] Various minor cleanups Reviewed-by: mchevalier, aivy, thartmann --- .../compiler/lib/ir_framework/RunInfo.java | 6 +- .../compiler/lib/ir_framework/Scenario.java | 4 +- .../lib/ir_framework/TestFramework.java | 4 +- .../ir_framework/driver/TestVMProcess.java | 15 ++- .../testvm/java/JavaMessageParser.java | 13 +- .../network/testvm/java/JavaMessages.java | 6 +- .../network/testvm/java/MethodTimes.java | 6 +- .../network/testvm/java/StdoutMessages.java | 1 + .../ir_framework/test/ArgumentsProvider.java | 2 +- .../lib/ir_framework/test/BaseTest.java | 4 +- .../lib/ir_framework/test/CheckedTest.java | 4 +- .../lib/ir_framework/test/CustomRunTest.java | 8 +- .../lib/ir_framework/test/DeclaredTest.java | 11 +- .../lib/ir_framework/test/TestVM.java | 85 ++++++------ .../inlinetypes/TestNullableInlineTypes.java | 2 - .../ir_framework/tests/TestDFlags.java | 126 +++++++++++++++--- 16 files changed, 205 insertions(+), 92 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/RunInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/RunInfo.java index 902e2d54774e..4d5961a19fee 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/RunInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/RunInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,8 +44,8 @@ public class RunInfo extends AbstractInfo { private final boolean hasMultipleTests; public RunInfo(List tests) { - super(tests.get(0).getTestMethod().getDeclaringClass()); - this.test = tests.get(0); + super(tests.getFirst().getTestMethod().getDeclaringClass()); + this.test = tests.getFirst(); this.testMethod = test.getTestMethod(); this.hasMultipleTests = tests.size() != 1; if (hasMultipleTests) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java index 014a65efc793..aeda075280bd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Scenario.java @@ -97,11 +97,13 @@ public Scenario(int index, String... flags) { * Add additional VM flags to this scenario. * * @param flags the additional scenario VM flags. + * @return the scenario object. */ - public void addFlags(String... flags) { + public Scenario addFlags(String... flags) { if (flags != null) { this.flags.addAll(Arrays.asList(flags)); } + return this; } /** diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 2076b9cf0889..6fe4b31b9ef0 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -158,7 +158,7 @@ public class TestFramework { public static final boolean VERBOSE = Boolean.getBoolean("Verbose"); public static final boolean PRINT_RULE_MATCHING_TIME = Boolean.getBoolean("PrintRuleMatchingTime"); private static final boolean TEST_LIST_IS_EMPTY = SystemProperty.getTestList().isEmpty(); - private static final boolean EXCLUDE_LIST_IS_EMPTY = SystemProperty.getExcludeList().isEmpty();; + private static final boolean EXCLUDE_LIST_IS_EMPTY = SystemProperty.getExcludeList().isEmpty(); private static final boolean REPORT_STDOUT = Boolean.getBoolean("ReportStdout"); // Only used for internal testing and should not be used for normal user testing. @@ -801,7 +801,7 @@ private void reportScenarioFailures(Map exceptionMap) { private static String getScenarioTitleAndFlags(Scenario scenario) { StringBuilder builder = new StringBuilder(); String title = "Scenario #" + scenario.getIndex(); - builder.append(title).append(System.lineSeparator()).append("=".repeat(title.length())) + builder.append(title).append(System.lineSeparator()).repeat("=", title.length()) .append(System.lineSeparator()); builder.append("Scenario flags: [").append(String.join(", ", scenario.getFlags())).append("]") .append(System.lineSeparator()); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index baed93594597..c77951755025 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -110,12 +110,16 @@ private TestVMData processTestVmResult(TestFrameworkSocket socket, boolean allow */ private void dumpTestVmOutputIfRequested() { if (DUMP_OUTPUT) { - System.out.println("Test VM Output"); - System.out.println("--------------"); - System.out.println(oa.getOutput()); + dumpTestVmOutput(); } } + private void dumpTestVmOutput() { + System.out.println("Test VM Output"); + System.out.println("--------------"); + System.out.println(oa.getOutput()); + } + private TestVMData readAndDumpTestVmData(TestFrameworkSocket socket, boolean allowNotCompilable) { String hotspotPidFileName = String.format("hotspot_pid%d.log", oa.pid()); TestVMData testVMData = socket.testVmData(hotspotPidFileName, allowNotCompilable); @@ -154,7 +158,8 @@ private TestVMException createTestVMExceptionForNonZeroExit(TestFrameworkSocket secondaryException = buildSecondaryExceptionInfo(e); } // Primary exception: non-zero Test VM exit. - return new TestVMException(buildExceptionInfo() + secondaryException); + String exceptionInfo = buildPrimaryExceptionInfo() + secondaryException; + return new TestVMException(exceptionInfo); } private String buildSecondaryExceptionInfo(RuntimeException e) { @@ -172,7 +177,7 @@ private String buildSecondaryExceptionInfo(RuntimeException e) { /** * Get more detailed information about the exception in a pretty format. */ - private String buildExceptionInfo() { + private String buildPrimaryExceptionInfo() { StringBuilder builder = new StringBuilder(); builder.append("Test VM exited with code ").append(oa.getExitValue()).append(System.lineSeparator()); if (hasFatalErrorMarker() || DUMP_OUTPUT) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java index 5b0c624720a2..0789009b2936 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java @@ -45,8 +45,8 @@ public class JavaMessageParser implements TestVmMessageParser { private static final Pattern TAG_PATTERN = Pattern.compile("^(\\[[^]]+])\\s*(.*)$"); private final List stdoutMessages; - private final List executedTests; private final Map methodTimes; + private final List executedTests; private final MultiLineParser vmInfoParser; private final MultiLineParser applicableIRRulesParser; @@ -100,11 +100,12 @@ private void parseTagLine(Matcher tagLineMatcher) { } private void parsePrintTimes(String message) { - String[] split = message.split(","); - TestFramework.check(split.length == 2, "unexpected format"); - String methodName = split[0]; + // When using @Run with multiple tests, we could have several commas in the message + int lastCommaIndex = message.lastIndexOf(','); + TestFramework.check(lastCommaIndex > 0 && lastCommaIndex < message.length() - 1, "unexpected format"); + String methodName = message.substring(0, lastCommaIndex); try { - long duration = Long.parseLong(split[1]); + long duration = Long.parseLong(message.substring(lastCommaIndex + 1)); methodTimes.put(methodName, duration); } catch (NumberFormatException e) { throw new TestFrameworkException("invalid duration", e); @@ -123,8 +124,8 @@ private void parseEndTag() { @Override public JavaMessages output() { return new JavaMessages(new StdoutMessages(stdoutMessages), - new ExecutedTests(executedTests), new MethodTimes(methodTimes), + new ExecutedTests(executedTests), applicableIRRulesParser.output(), vmInfoParser.output()); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java index e817610f4410..c7380205974e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java @@ -28,16 +28,16 @@ */ public class JavaMessages { private final StdoutMessages stdoutMessages; - private final ExecutedTests executedTests; private final MethodTimes methodTimes; + private final ExecutedTests executedTests; private final ApplicableIRRules applicableIrRules; private final VMInfo vmInfo; - JavaMessages(StdoutMessages stdoutMessages, ExecutedTests executedTests, MethodTimes methodTimes, + JavaMessages(StdoutMessages stdoutMessages, MethodTimes methodTimes, ExecutedTests executedTests, ApplicableIRRules applicableIrRules, VMInfo vmInfo) { this.stdoutMessages = stdoutMessages; - this.executedTests = executedTests; this.methodTimes = methodTimes; + this.executedTests = executedTests; this.applicableIrRules = applicableIrRules; this.vmInfo = vmInfo; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java index 1b4cad522702..88641256b35f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java @@ -54,9 +54,11 @@ public void print() { int maxDurationsWidth = maxDurationsWidth(); List> sortedMethodTimes = sortByDurationAsc(); + // printf() has no '*' as dynamic-width specifier, so the calculated widths are inserted into the format string. + String format = "- %-" + (maxWidthNames + 3) + "s %" + maxDurationsWidth + "d ms%n"; + for (Map.Entry entry : sortedMethodTimes) { - System.out.printf("- %-" + (maxWidthNames + 3) + "s %" + maxDurationsWidth + "d ns%n", - entry.getKey() + ":", entry.getValue()); + System.out.printf(format, entry.getKey() + ":", entry.getValue()); } System.out.println(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java index 11b23ad42370..9118108260d3 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java @@ -50,5 +50,6 @@ public void print() { for (String message : messages) { System.out.println("- " + message); } + System.out.println(); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java index f868fa2b82fb..c5faeed4040b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java @@ -27,7 +27,7 @@ * This interface provides arguments (and can set fields) for a test method. Different implementations are chosen * based on the @Arguments annotation for the @Test method. */ -interface ArgumentsProvider { +public interface ArgumentsProvider { /** * Compute arguments (and possibly set fields) for a test method. * diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java index 8b693ddcf177..0e5c4f799871 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public BaseTest(DeclaredTest test, boolean skip) { @Override public String toString() { - return "Base Test: @Test " + testMethod.getName(); + return "@Test: " + testMethod.getName(); } @Override diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/CheckedTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/CheckedTest.java index 8959dbac2eea..287960d5703c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/CheckedTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/CheckedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ public CheckedTest(DeclaredTest test, Method checkMethod, Check checkSpecificati @Override public String toString() { - return "Checked Test: @Check " + checkMethod.getName() + " - @Test: " + testMethod.getName(); + return "@Test: " + testMethod.getName() + " -> @Check: " + checkMethod.getName(); } @Override diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/CustomRunTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/CustomRunTest.java index bd88d44ce44b..98a829fcc015 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/CustomRunTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/CustomRunTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,9 +61,9 @@ public CustomRunTest(Method runMethod, Warmup warmUpAnno, Run runSpecification, @Override public String toString() { - String s = "Custom Run Test: @Run: " + runMethod.getName() + " - @Test"; + String s = "@Run: " + runMethod.getName() + " -> @Test"; if (tests.size() == 1) { - s += ": " + tests.get(0).getTestMethod().getName(); + s += ": " + tests.getFirst().getTestMethod().getName(); } else { s += "s: {" + tests.stream().map(t -> t.getTestMethod().getName()) .collect(Collectors.joining(",")) + "}"; @@ -105,7 +105,7 @@ protected void compileTest() { } private void compileSingleTest() { - DeclaredTest test = tests.get(0); + DeclaredTest test = tests.getFirst(); if (shouldCompile(test)) { if (isWaitForCompilation(test)) { waitForCompilation(test); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java index 15cd68bd0e3b..81143b6c2540 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,19 +34,20 @@ public class DeclaredTest { private final Method testMethod; private final ArgumentsProvider argumentsProvider; - private final int warmupIterations; private final CompLevel compLevel; + private final int warmupIterations; private final boolean allowNotCompilable; private Method attachedMethod; - public DeclaredTest(Method testMethod, ArgumentsProvider argumentsProvider, CompLevel compLevel, int warmupIterations, boolean allowNotCompilable) { + public DeclaredTest(Method testMethod, ArgumentsProvider argumentsProvider, CompLevel compLevel, int warmupIterations, + boolean allowNotCompilable) { // Make sure we can also call non-public or public methods in package private classes testMethod.setAccessible(true); this.testMethod = testMethod; - this.compLevel = compLevel; - this.allowNotCompilable = allowNotCompilable; this.argumentsProvider = argumentsProvider; + this.compLevel = compLevel; this.warmupIterations = warmupIterations; + this.allowNotCompilable = allowNotCompilable; this.attachedMethod = null; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index 07c1397749aa..b7c0a2201a5b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -95,8 +95,8 @@ assertions from main() of your test! private static final boolean PRINT_TIMES = Boolean.getBoolean("PrintTimes") || VERBOSE; public static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); static final boolean EXCLUDE_RANDOM = Boolean.getBoolean("ExcludeRandom"); - private static final String TESTLIST = SystemProperty.getTestList(); - private static final String EXCLUDELIST = SystemProperty.getExcludeList(); + private static final String TEST_LIST = SystemProperty.getTestList(); + private static final String EXCLUDE_LIST = SystemProperty.getExcludeList(); private static final boolean DUMP_REPLAY = Boolean.getBoolean("DumpReplay"); private static final boolean GC_AFTER = Boolean.getBoolean("GCAfter"); private static final boolean SHUFFLE_TESTS = Boolean.parseBoolean(System.getProperty("ShuffleTests", "true")); @@ -122,8 +122,8 @@ assertions from main() of your test! private TestVM(Class testClass) { TestRun.check(testClass != null, "Test class cannot be null"); this.testClass = testClass; - this.testList = createTestFilterList(TESTLIST, testClass); - this.excludeList = createTestFilterList(EXCLUDELIST, testClass); + this.testList = createTestFilterList(TEST_LIST, testClass); + this.excludeList = createTestFilterList(EXCLUDE_LIST, testClass); if (PRINT_VALID_IR_RULES) { irMatchRulePrinter = new ApplicableIRRulesPrinter(); @@ -136,19 +136,20 @@ private TestVM(Class testClass) { * Parse "test1,test2,test3" into a list. */ private static List createTestFilterList(String list, Class testClass) { - List filterList = null; - if (!list.isEmpty()) { - String classPrefix = testClass.getSimpleName() + "."; - filterList = new ArrayList<>(Arrays.asList(list.split(","))); - for (int i = filterList.size() - 1; i >= 0; i--) { - String test = filterList.get(i); - if (test.indexOf(".") > 0) { - if (test.startsWith(classPrefix)) { - test = test.substring(classPrefix.length()); - filterList.set(i, test); - } else { - filterList.remove(i); - } + if (list.isEmpty()) { + return new ArrayList<>(); + } + + String classPrefix = testClass.getSimpleName() + "."; + List filterList = new ArrayList<>(Arrays.asList(list.split(","))); + for (int i = filterList.size() - 1; i >= 0; i--) { + String test = filterList.get(i); + if (test.indexOf(".") > 0) { + if (test.startsWith(classPrefix)) { + test = test.substring(classPrefix.length()); + filterList.set(i, test); + } else { + filterList.remove(i); } } } @@ -295,7 +296,7 @@ private void addBaseTests() { try { Arguments argumentsAnno = getAnnotation(m, Arguments.class); TestFormat.check(argumentsAnno != null || m.getParameterCount() == 0, "Missing @Arguments annotation to define arguments of " + m); - BaseTest baseTest = new BaseTest(test, shouldExcludeTest(m.getName())); + BaseTest baseTest = new BaseTest(test, shouldExcludeTest(m)); allTests.add(baseTest); if (PRINT_VALID_IR_RULES) { irMatchRulePrinter.emitApplicableIRRules(m, baseTest.isSkipped()); @@ -308,17 +309,22 @@ private void addBaseTests() { } /** - * Check if user wants to exclude this test by checking the -DTest and -DExclude lists. + * A test is excluded from execution if: + * - -DTest does not list the method + * - -DExclude lists the method */ - private boolean shouldExcludeTest(String testName) { - boolean hasTestList = testList != null; - boolean hasExcludeList = excludeList != null; - if (hasTestList) { - return !testList.contains(testName) || (hasExcludeList && excludeList.contains(testName)); - } else if (hasExcludeList) { - return excludeList.contains(testName); - } - return false; + private boolean shouldExcludeTest(Method testMethod) { + String testName = testMethod.getName(); + return isNotOnTestList(testName) || + isOnExcludeList(testName); + } + + private boolean isNotOnTestList(String testName) { + return !testList.isEmpty() && !testList.contains(testName); + } + + private boolean isOnExcludeList(String testName) { + return excludeList.contains(testName); } /** @@ -541,7 +547,7 @@ private void addSetupMethod(Method m) { } /** - * Setup @Test annotated method an add them to the declaredTests map to have a convenient way of accessing them + * Setup @Test annotated method and add them to the declaredTests map to have a convenient way of accessing them * once setting up a framework test (base checked, or custom run test). */ private void setupDeclaredTests() { @@ -693,7 +699,7 @@ private void addCheckedTest(Method m, Check checkAnno, Run runAnno) { + "checked test " + m); CheckedTest.Parameter parameter = getCheckedTestParameter(m, testMethod); dontCompileAndDontInlineMethod(m); - CheckedTest checkedTest = new CheckedTest(test, m, checkAnno, parameter, shouldExcludeTest(testMethod.getName())); + CheckedTest checkedTest = new CheckedTest(test, m, checkAnno, parameter, shouldExcludeTest(testMethod)); allTests.add(checkedTest); if (PRINT_VALID_IR_RULES) { // Only need to emit IR verification information if IR verification is actually performed. @@ -752,8 +758,8 @@ private void addCustomRunTest(Method m, Run runAnno) { checkCustomRunTest(m, testName, testMethod, test, runAnno.mode()); test.setAttachedMethod(m); tests.add(test); - // Only exclude custom run test if all test methods excluded - shouldExcludeTest &= shouldExcludeTest(testMethod.getName()); + // Only exclude custom run test if all its associated test methods are excluded + shouldExcludeTest &= shouldExcludeTest(testMethod); } catch (TestFormatException e) { // Logged, continue. } @@ -864,11 +870,12 @@ private void runTests() { // Execute all tests and keep track of each exception that is thrown. These are then reported once all tests // are executing. This prevents a premature exit without running all tests. for (AbstractTest test : testList) { + String testName = test.getName(); if (VERBOSE) { - System.out.println("Run " + test.toString()); + System.out.println("Run \"" + testName + "\""); } if (testFilterPresent) { - TestVmSocket.sendWithTag(MessageTag.TEST_LIST, "Run " + test.toString()); + TestVmSocket.sendWithTag(MessageTag.TEST_LIST, test.toString()); } try { test.run(); @@ -876,18 +883,18 @@ private void runTests() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); - builder.append(test).append(":").append(System.lineSeparator()).append(sw) + builder.append("Failed test: ").append(test).append(":").append(System.lineSeparator()).append(sw) .append(System.lineSeparator()).append(System.lineSeparator()); failures++; } if (PRINT_TIMES) { long endTime = System.nanoTime(); - long duration = (endTime - startTime); + long durationMs = (endTime - startTime) / 1_000_000; if (VERBOSE) { - System.out.println("Done " + test.getName() + ": " + duration + " ns = " + (duration / 1_000_000) + " ms"); + System.out.println("Done " + testName + ": " + durationMs + " ms"); } // Will be correctly formatted later. - TestVmSocket.sendWithTag(MessageTag.PRINT_TIMES, test.getName() + "," + duration); + TestVmSocket.sendWithTag(MessageTag.PRINT_TIMES, test + "," + durationMs); } if (GC_AFTER) { System.out.println("doing GC"); @@ -904,7 +911,7 @@ private void runTests() { } private boolean testFilterPresent() { - return testList != null || excludeList != null; + return !testList.isEmpty() || !excludeList.isEmpty(); } enum TriState { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java index 0a641ba2961a..a4a68b5f9ea3 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java @@ -3018,7 +3018,6 @@ public static Object hide(Object obj) { } // Test that the ConstraintCastNode::Ideal transformation propagates null-free information - /* TODO 8389088: Re-enable once fixed. @Test public MyValue1 test103() { Object obj = hide(null); @@ -3029,7 +3028,6 @@ public MyValue1 test103() { public void test103_verifier() { Asserts.assertEQ(test103(), null); } - */ // Test null restricted fields diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestDFlags.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestDFlags.java index 1f176efff0f9..f1bf34be0495 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestDFlags.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestDFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,31 +23,92 @@ package ir_framework.tests; -import compiler.lib.ir_framework.IR; -import compiler.lib.ir_framework.IRNode; -import compiler.lib.ir_framework.Test; -import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; /* * @test * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless * @summary Sanity test remaining framework property/D flags with non-default values. We do two runs, one time with * VerifyIR=false and one time with VerifyIR=true. * @library /test/lib / - * @run main/othervm -DFlipC1C2=true -DExcludeRandom=true -DVerifyVM=true -DDumpReplay=true -DVerbose=true - * -DShuffleTests=false -DReproduce=true -DReportStdout=true -DGCAfter=true -DPrintTimes=true - * -DIgnoreCompilerControls=true -DExcludeRandom=true -DVerifyIR=true - * -DPreferCommandLineFlags=true -DPrintRuleMatchingTime=true ir_framework.tests.TestDFlags - * @run main/othervm -DFlipC1C2=true -DExcludeRandom=true -DVerifyVM=true -DDumpReplay=true -DVerbose=true - * -DShuffleTests=false -DReproduce=true -DReportStdout=true -DGCAfter=true -DPrintTimes=true - * -DIgnoreCompilerControls=true -DExcludeRandom=true -DVerifyIR=false - * -DPreferCommandLineFlags=true -DPrintRuleMatchingTime=true ir_framework.tests.TestDFlags + * @run driver ${test.main.class} spawn */ public class TestDFlags { - public static void main(String[] args) { - TestFramework.run(); + public static void main(String[] args) throws Exception { + if (args.length > 0) { + try { + // We pass all non-default except for VerifyIR: + execute("-DFlipC1C2=true", + "-DExcludeRandom=true", + "-DVerifyVM=true", + "-DDumpReplay=true", + "-DVerbose=true", + "-DShuffleTests=false", + "-DReportStdout=true", + "-DGCAfter=true", + "-DPrintTimes=true", + "-DIgnoreCompilerControls=true", + "-DVerifyIR=true", // default -> apply IR verification + "-DPreferCommandLineFlags=true"); + + execute("-DFlipC1C2=true", + "-DExcludeRandom=true", + "-DVerifyVM=true", + "-DDumpReplay=true", + "-DVerbose=true", + "-DShuffleTests=false", + "-DReportStdout=true", + "-DGCAfter=true", + "-DPrintTimes=true", + "-DIgnoreCompilerControls=true", + "-DVerifyIR=false", // non-default -> no IR verification + "-DPreferCommandLineFlags=true"); + } finally { + deleteReplayFiles(); + } + } else { + TestFramework.run(); + } } + private static void execute(String... propertyFlags) throws Exception { + // Property flags are usually added as additionally options when running a jtreg test. To simulate that, we + // explicitly need to set the -Dtest.java.opts to propagate them to the Test VM. When we only specify the + // property flags in '@run main/othervm', they are not passed to the Test VM. + List command = new ArrayList<>(); + // Set jtreg set properties explicitly since we spawn a separate VM + command.add("-Dtest.class.path=" + Utils.TEST_CLASS_PATH); + command.add("-Dtest.jdk=" + Utils.TEST_JDK); + + command.add("-Dtest.java.opts=" + String.join(" ", propertyFlags)); // Properties for Test VM + command.addAll(List.of(propertyFlags)); // Properties for Driver VM + command.add(TestDFlags.class.getName()); + ProcessTools.executeTestJava(command).shouldHaveExitValue(0); + } + + // Clean up the many replay files generated by using -DDumpReplay=true. + private static void deleteReplayFiles() { + Path scratchDir = Path.of(System.getProperty("user.dir")); + + try (DirectoryStream files = Files.newDirectoryStream(scratchDir, "replay_pid*_compid*.log")) { + for (Path file : files) { + Files.deleteIfExists(file); + } + } catch (IOException e) { + throw new RuntimeException("Could not delete replay files from " + scratchDir, e); + } + } + + @Test @IR(failOn = IRNode.STORE) public int c1() { @@ -75,5 +136,40 @@ public void c2_3() { for (int i = 0; i < 100; i++) { } } + + @Test + @IR(failOn = IRNode.STORE) + public void test1() { + } + + @Run(test = "test1") + public void runTest1() { + test1(); + } + + @Test + @IR(failOn = IRNode.STORE) + public void test2() { + } + + @Check(test = "test2") + public void checkTest2() { + } + + @Test + @IR(failOn = IRNode.STORE) + public void test3() { + } + + @Test + @IR(failOn = IRNode.STORE) + public void test4() { + } + + @Run(test = {"test3", "test4"}) + public void runTest3And4() { + test3(); + test4(); + } } From 34f80b89a5ddd940da221999cdbcfbb746340b55 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 2 Sep 2026 13:52:11 +0000 Subject: [PATCH 204/223] 8389843: Synchronize ClassFile API verifier up to jdk-28+11 Reviewed-by: asotona --- .../classfile/impl/RawBytecodeHelper.java | 20 ++- .../impl/verifier/VerificationFrame.java | 10 +- .../impl/verifier/VerificationTable.java | 62 ++++++--- .../classfile/impl/verifier/VerifierImpl.java | 35 +++-- .../classfile/impl/verifier/verifier.md | 2 +- test/jdk/jdk/classfile/VerifierSelfTest.java | 122 +++++++++++++++++- 6 files changed, 206 insertions(+), 45 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 3f528ebd6b1c..9209196f98fe 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -404,13 +404,27 @@ public int getIntUnchecked(int bci) { } // non-wide branches + // dest() on validated payload only public int dest() { - return bci + getShortUnchecked(bci + 1); + int offset = getOffsetS2(); + assert -0xFFFF <= offset && offset <= 0xFFFF; + return bci + offset; + } + + public int getOffsetS2() { + return getShortUnchecked(bci + 1); } // goto_w and jsr_w + // destW() on validated payload only public int destW() { - return bci + getIntUnchecked(bci + 1); + int offset = getOffsetS4(); + assert -0xFFFF <= offset && offset <= 0xFFFF; + return bci + offset; + } + + public int getOffsetS4() { + return getIntUnchecked(bci + 1); } // *load, *store, iinc @@ -477,7 +491,7 @@ private int checkSpecialInstruction(int bci, int end, int code) { } } else if (code == LOOKUPSWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 2 * 4 < end) { + if (alignedBci + 2 * 4 <= end) { int npairs = getIntUnchecked(alignedBci + 4); if (npairs >= 0) { long l = alignedBci - bci + (2L + 2L * npairs) * 4L; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java index d096b78a67d4..4417dbaaa401 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.classfile.constantpool.Utf8Entry; import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import jdk.internal.classfile.impl.TemporaryConstantPool; @@ -56,7 +57,7 @@ public VerificationFrame(int offset, int flags, int locals_size, int stack_size, this._flags = flags; this._locals = locals; this._stack = stack; - this._assert_unset_fields = assert_unset_fields; + set_assert_unset_fields(assert_unset_fields); this._verifier = v; } @@ -122,7 +123,7 @@ Set assert_unset_fields() { } void set_assert_unset_fields(Set table) { - _assert_unset_fields = table; + _assert_unset_fields = new HashSet<>(table); } // Called when verifying putfields to mark strict instance fields as satisfied @@ -184,6 +185,9 @@ void push_stack(VerificationType type) { if (_stack_size >= _max_stack) { _verifier.verifyError("Operand stack overflow"); } + if (type.is_uninitialized_this(_verifier)) { + _flags |= FLAG_THIS_UNINIT; + } _stack[_stack_size++] = type; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java index fbb4eb9c9edb..ef18c4ff8c48 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,7 +135,14 @@ boolean match_stackmap(VerificationFrame frame, int target, int frame_index, boo return result; } - void check_jump_target(VerificationFrame frame, int target) { + void check_jump_target(VerificationFrame frame, int bci, int offset) { + // Jump targets must be within the method and the method size is limited. See JVMS 4.11 + int min_offset = -1 * 0xFFFF; + if (offset < min_offset || offset > 0xFFFF) { + _verifier.verifyError("Illegal target of jump or branch (bci %d + offset %d)".formatted(bci, offset)); + return; + } + int target = bci + offset; boolean match = match_stackmap(frame, target, true, false); if (!match || (target < 0 || target >= _code_length)) { _verifier.verifyError(String.format("Inconsistent stackmap frames at branch target %d", target)); @@ -155,6 +162,7 @@ static class StackMapReader { final Set strictFields; Set _assert_unset_fields_buffer; boolean _first; + private boolean _uninit_in_prev_frame_locals; void check_verification_type_array_size(int size, int max_size) { if (size < 0 || size > max_size) { @@ -223,6 +231,15 @@ public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, _cp = null; _frame_count = 0; } + + VerificationType[] locals = init_frame.locals(); + _uninit_in_prev_frame_locals = false; + for (int i = 0; i < init_frame.locals_size(); i++) { + if (locals[i].is_uninitialized_this(_verifier)) { + _uninit_in_prev_frame_locals = true; + break; + } + } } void check_offset(VerificationFrame frame) { @@ -252,7 +269,8 @@ int chop(VerificationType[] locals, int length, int chops) { return pos+1; } - VerificationType parse_verification_type(int[] flags) { + VerificationType parse_verification_type(int[] flags, boolean parsing_locals) { + assert flags != null; int tag = _stream.get_u1(); if (tag < ITEM_UNINITIALIZED_THIS) { return VerificationType.from_tag(tag, _verifier); @@ -266,8 +284,12 @@ VerificationType parse_verification_type(int[] flags) { return VerificationType.reference_type(_cp.classNameAt(class_index)); } if (tag == ITEM_UNINITIALIZED_THIS) { - if (flags != null) { - flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; + flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; + // An uninitializedThis in the locals array can sometimes be preserved + // between frames while uninitializedThis in the stack cannot as the stack + // is cleared. Chop and Full frames need special handling. + if (parsing_locals) { + _uninit_in_prev_frame_locals = true; } return VerificationType.uninitialized_this_type; } @@ -332,7 +354,10 @@ VerificationFrame next_helper() { offset = _prev_frame.offset() + frame_type + 1; locals = _prev_frame.locals(); } - frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier); + + int flags = _uninit_in_prev_frame_locals ? 1 : 0; + + frame = new VerificationFrame(offset, flags, _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier); if (_first && locals != null) { frame.copy_locals(_prev_frame); } @@ -351,13 +376,14 @@ VerificationFrame next_helper() { } VerificationType[] stack = new VerificationType[2]; int stack_size = 1; - stack[0] = parse_verification_type(null); + int[] flags = {_uninit_in_prev_frame_locals ? 1 : 0}; + stack[0] = parse_verification_type(flags, false /*parsing_locals*/); if (stack[0].is_category2()) { stack[1] = stack[0].to_category2_2nd(_verifier); stack_size = 2; } check_verification_type_array_size(stack_size, _max_stack); - frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); + frame = new VerificationFrame(offset, flags[0], _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); if (_first && locals != null) { frame.copy_locals(_prev_frame); } @@ -380,13 +406,14 @@ VerificationFrame next_helper() { } VerificationType[] stack = new VerificationType[2]; int stack_size = 1; - stack[0] = parse_verification_type(null); + int[] flags = {_uninit_in_prev_frame_locals ? 1 : 0}; + stack[0] = parse_verification_type(flags, false /*parsing_locals*/); if (stack[0].is_category2()) { stack[1] = stack[0].to_category2_2nd(_verifier); stack_size = 2; } check_verification_type_array_size(stack_size, _max_stack); - frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); + frame = new VerificationFrame(offset, flags[0], _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier); if (_first && locals != null) { frame.copy_locals(_prev_frame); } @@ -398,14 +425,16 @@ VerificationFrame next_helper() { int length = _prev_frame.locals_size(); int chops = SAME_FRAME_EXTENDED - frame_type; int new_length = length; - int flags = _prev_frame.flags(); + int flags = _uninit_in_prev_frame_locals ? 1 : 0; if (chops != 0) { new_length = chop(locals, length, chops); check_verification_type_array_size(new_length, _max_locals); flags = 0; + _uninit_in_prev_frame_locals = false; for (int i=0; i 0) { @@ -464,7 +494,7 @@ VerificationFrame next_helper() { } int i; for (i=0; i strict_fields = new HashSet<>(); - if (m.name().equals(ConstantDescs.INIT_NAME)) { + // Hotspot runtime filters STRICT_INIT flag by classfile version, ClassFile API needs extra check + if (m.name().equals(ConstantDescs.INIT_NAME) && supports_strict_fields(_klass)) { for (var fs : current_class().clm.fields()) { if (fs.flags().has(AccessFlag.STRICT_INIT) && !fs.flags().has(AccessFlag.STATIC)) { var new_field = TemporaryConstantPool.INSTANCE.nameAndTypeEntry(fs.fieldName(), fs.fieldType()); @@ -331,6 +332,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } } + Set read_only_strict_fields = new HashSet<>(strict_fields); VerificationFrame current_frame = new VerificationFrame(max_locals, max_stack, strict_fields, this); VerificationType return_type = current_frame.set_locals_from_arg(m, current_type()); int stackmap_index = 0; @@ -345,7 +347,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verify_local_variable_table(code_length, code_data); var reader = new VerificationTable.StackMapReader(stackmap_data, code_data, code_length, current_frame, - (char) max_locals, (char) max_stack, strict_fields, cp, this); + (char) max_locals, (char) max_stack, read_only_strict_fields, cp, this); VerificationTable stackmap_table = new VerificationTable(reader, cp, this); var bcs = code.start(); @@ -361,7 +363,6 @@ void verify_method(VerificationWrapper.MethodWrapper m) { boolean verified_exc_handlers = false; { int index; - int target; VerificationType type, type2 = null; VerificationType atype; if (bcs.isWide()) { @@ -1069,9 +1070,8 @@ void verify_method(VerificationWrapper.MethodWrapper m) { case IFLE: current_frame.pop_stack( VerificationType.integer_type); - target = bcs.dest(); stackmap_table.check_jump_target( - current_frame, target); + current_frame, bcs.bci(), bcs.getOffsetS2()); no_control_flow = false; break; case IF_ACMPEQ : case IF_ACMPNE : @@ -1080,19 +1080,16 @@ void verify_method(VerificationWrapper.MethodWrapper m) { case IFNULL : case IFNONNULL : current_frame.pop_stack(object_type()); - target = bcs.dest(); stackmap_table.check_jump_target - (current_frame, target); + (current_frame, bcs.bci(), bcs.getOffsetS2()); no_control_flow = false; break; case GOTO : - target = bcs.dest(); stackmap_table.check_jump_target( - current_frame, target); + current_frame, bcs.bci(), bcs.getOffsetS2()); no_control_flow = true; break; case GOTO_W : - target = bcs.destW(); stackmap_table.check_jump_target( - current_frame, target); + current_frame, bcs.bci(), bcs.getOffsetS4()); no_control_flow = true; break; case TABLESWITCH : case LOOKUPSWITCH : @@ -1154,11 +1151,9 @@ void verify_method(VerificationWrapper.MethodWrapper m) { case INVOKEVIRTUAL : case INVOKESPECIAL : case INVOKESTATIC : - this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); - no_control_flow = false; break; case INVOKEINTERFACE : case INVOKEDYNAMIC : - this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); + this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, cp, stackmap_table); no_control_flow = false; break; case NEW : { @@ -1475,12 +1470,11 @@ void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, Ver } } } - int target = bci + default_offset; - stackmap_table.check_jump_target(current_frame, target); + stackmap_table.check_jump_target(current_frame, bci, default_offset); for (int i = 0; i < keys; i++) { aligned_bci = VerificationBytecodes.align(bcs.bci() + 1); - target = bci + bcs.getIntUnchecked(aligned_bci + (3+i*delta)*4); - stackmap_table.check_jump_target(current_frame, target); + int offset = bcs.getIntUnchecked(aligned_bci + (3+i*delta)*4); + stackmap_table.check_jump_target(current_frame, bci, offset); } } @@ -1533,7 +1527,8 @@ void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_ // Set the type to the current type so the is_assignable check passes. stack_object_type = current_type(); - if (fd.flags().has(AccessFlag.STRICT_INIT)) { + // Hotspot runtime filters STRICT_INIT flag by classfile version, ClassFile API needs extra check + if (fd.flags().has(AccessFlag.STRICT_INIT) && supports_strict_fields(_klass)) { current_frame.satisfy_unset_field(fd.fieldName(), fd.fieldType()); } } @@ -1607,7 +1602,7 @@ static boolean is_same_or_direct_interface(VerificationWrapper klass, Verificati return false; } - boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, VerificationFrame current_frame, boolean in_try_block, boolean this_uninit, VerificationType return_type, ConstantPoolWrapper cp, VerificationTable stackmap_table) { + boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, VerificationFrame current_frame, boolean in_try_block, boolean this_uninit, ConstantPoolWrapper cp, VerificationTable stackmap_table) { // Make sure the constant pool item is the right type int index = bcs.getIndexU2(); int opcode = bcs.opcode(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/verifier.md b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/verifier.md index 1899f7b86a37..dda8dea1e335 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/verifier.md +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/verifier.md @@ -17,4 +17,4 @@ for example, this should not fail upon encountering new language features, and should at best include all new checks hotspot has as long as the required information are accessible to the Class-File API. -Last sync: jdk-26+5, July 3rd 2025 +Last sync: jdk-28+11, Aug 14th 2026 diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index 1f0d95394722..e514161a3dca 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -32,8 +32,7 @@ import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; -import static java.lang.classfile.ClassFile.ACC_STATIC; -import static java.lang.classfile.ClassFile.JAVA_8_VERSION; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; @@ -61,6 +60,7 @@ import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.UnboundAttribute; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -508,4 +508,122 @@ void testInvokeSpecialInterfacePatch() { assertTrue(errors.getFirst().getMessage().contains("interface method to invoke is not in a direct superinterface"), errors.getFirst().getMessage()); } } + + @Test // JDK-8357037 + void testCodeEndsWithSwitch() { + var testClass = ClassDesc.of("Test"); + var context = ClassFile.of(); + var bytes = context.build(testClass, clb -> clb + .withVersion(JAVA_28_VERSION, 0) + .withMethodBody("tableSwitchFoo", MTD_void, 0, cob -> { + Label skip = cob.newLabel(); + cob.goto_(skip); + Label back = cob.newBoundLabel(); + cob.return_() + .labelBinding(skip) + .iconst_0() + .tableswitch(0, 2, back, List.of()); + }) + .withMethodBody("lookupSwitchFoo", MTD_void, 0, cob -> { + Label skip = cob.newLabel(); + cob.goto_(skip); + Label back = cob.newBoundLabel(); + cob.return_() + .labelBinding(skip) + .iconst_0() + .lookupswitch(back, List.of()); + })); + assertEquals(List.of(), context.verify(bytes)); + } + + @Test // JDK-8388631 + void testControlFlowAlias() { + var testName = "Test"; + var testDesc = ClassDesc.of(testName); + var bytes = ClassFile.of(StackMapsOption.DROP_STACK_MAPS).build(testDesc, clb -> clb + .withVersion(latestMajorVersion(), PREVIEW_MINOR_VERSION) + .withFlags(ACC_PUBLIC | ACC_IDENTITY) + .withField("f", CD_int, ACC_STRICT_INIT) + .withMethodBody(INIT_NAME, MethodTypeDesc.of(CD_void, CD_boolean), 0, cob -> { + Label ifEnd = cob.newLabel(); + cob.iload(1) + .ifeq(ifEnd) + .aload(0) + .iconst_1() + .putfield(testDesc, "f", CD_int) + .labelBinding(ifEnd) + .aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .return_() + .with(StackMapTableAttribute.of(List.of(StackMapFrameInfo.of(ifEnd, + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(), + List.of(cob.constantPool().nameAndTypeEntry("f", CD_int)))))); + })); + ClassModel cm = ClassFile.of().parse(bytes); + var stackMapsTable = cm.methods().getFirst().findAttribute(Attributes.code()).orElseThrow() + .findAttribute(Attributes.stackMapTable()).orElseThrow(); + assertNotEquals(246, stackMapsTable.entries().getFirst().frameType()); + assertNotEquals(List.of(), ClassFile.of().verify(cm)); // field f not initialized + } + + @Test // JDK-8389840 + @Disabled // Need StackMapFrameInfo.of fix + void testUninitializedThisOnStackOnly() { + var testName = "Test"; + var testDesc = ClassDesc.of(testName); + var bytes = ClassFile.of(StackMapsOption.DROP_STACK_MAPS).build(testDesc, clb -> clb + .withVersion(latestMajorVersion(), PREVIEW_MINOR_VERSION) + .withFlags(ACC_PUBLIC | ACC_IDENTITY) + .withField("f", CD_int, ACC_STRICT_INIT) + .withMethodBody(INIT_NAME, MTD_void, 0, cob -> { + List frames = new ArrayList<>(); + cob.aload(0) // stack for invokespecial + .dup() // stack for putfield + .iconst_4() + .iconst_m1() // stack for astore + .istore(0) // nuke uninitializedThis from locals + .iconst_3(); // stack for branch + var elseLabel = cob.newLabel(); + var endIfLabel = cob.newLabel(); + cob.ifeq(elseLabel) + .putfield(testDesc, "f", CD_int) + .goto_(endIfLabel) + .labelBinding(elseLabel); + frames.add(StackMapFrameInfo.of(elseLabel, + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS, + StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS, + StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(cob.constantPool().nameAndTypeEntry("f", CD_int)))); + cob.putfield(testDesc, "f", CD_int) + .labelBinding(endIfLabel); + frames.add(StackMapFrameInfo.of(endIfLabel, + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS), + List.of())); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + var else2Label = cob.newLabel(); + var endIf2Label = cob.newLabel(); + cob.iconst_1() + .ifeq(else2Label) + .nop() + .goto_(endIf2Label) + .labelBinding(else2Label); + frames.add(StackMapFrameInfo.of(else2Label, + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(), + List.of())); + cob.nop() + .labelBinding(endIf2Label); + frames.add(StackMapFrameInfo.of(endIf2Label, + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + List.of(), + List.of())); + cob.return_() + .with(StackMapTableAttribute.of(frames)); + })); + + assertEquals(List.of(), ClassFile.of().verify(bytes)); + } } From fb015757e60d74941a64ac458218d180f69f6fcf Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 2 Sep 2026 14:56:05 +0000 Subject: [PATCH 205/223] 8380425: os::print_location should handle markword printing with COH Reviewed-by: stuefe, coleenp, dholmes --- src/hotspot/share/runtime/os.cpp | 15 ++++- test/hotspot/gtest/runtime/test_os.cpp | 76 ++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 9c77c5e30abf..aaeab6119d3c 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1339,8 +1339,21 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } // Compressed klass needs to be decoded first. - // Todo: questionable for COH - can we do this better? #ifdef _LP64 + if (UseCompactObjectHeaders) { + markWord mw = (markWord)(uintptr_t)(addr); + static constexpr uintptr_t valhalla_reserved_bits_in_place = right_n_bits(markWord::valhalla_reserved_bits) + << markWord::valhalla_reserved_shift; + static constexpr uintptr_t markbits_must_be_zero = valhalla_reserved_bits_in_place | markWord::self_fwd_bit_in_place; + if (mw.has_no_hash() && (mw.value() & markbits_must_be_zero) == 0 && Klass::is_valid(mw.klass_without_asserts())) { + st->print(PTR_FORMAT " looks like a valid markword: ", p2i(addr)); + mw.print_on(st); + st->print(" "); + mw.klass()->print_on(st); + return; + } + } + if (((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) { narrowKlass narrow_klass = (narrowKlass)(uintptr_t)addr; Klass* k = CompressedKlassPointers::decode_without_asserts(narrow_klass); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 75d4f7bb9d57..17eb611bbd8b 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -29,6 +29,7 @@ #include "runtime/thread.hpp" #include "runtime/threads.hpp" #include "testutils.hpp" +#include "threadHelper.inline.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -123,6 +124,81 @@ TEST_VM(os, page_size_for_region_unaligned) { } } +TEST_VM(os, test_print_markword) { +#ifdef _LP64 + if (UseCompactObjectHeaders) { + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative invm(THREAD); + markWord m0 = vmClasses::Byte_klass()->prototype_header(); + const struct { markWord mw; const char* expected; } patterns[] = { + { markWord(0), "is null"}, + { m0, "mark(is_unlocked no_hash age=0) java.lang.Byte" }, + { m0.set_age(2), "age=2" }, + { m0.copy_set_hash(0x12345), "is an unknown value" } + }; + constexpr int nmark = sizeof(patterns) / sizeof(patterns[0]); + for (int i = 0; i < nmark; i++) { + stringStream st; + MutexLocker lock(ClassLoaderDataGraph_lock); + os::print_location(&st, (intptr_t) patterns[i].mw.to_pointer(), true); + ASSERT_THAT(st.base(), testing::HasSubstr(patterns[i].expected)); + } + } +#endif +} + +static void assert_test_pattern(oop& obj, const char* pattern, bool is_present=true) { + stringStream st; + os::print_location(&st, p2i(obj), true); + if (is_present) { + ASSERT_THAT(st.base(), testing::HasSubstr(pattern)); + } else { + ASSERT_THAT(st.base(), testing::Not(testing::HasSubstr(pattern))); + } +} + +TEST_VM(os, test_print_location) { + + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative invm(THREAD); + + oop obj = vmClasses::Byte_klass()->allocate_instance(THREAD); + + { + // wizard mode off, so don't print markword + MutexLocker lock(ClassLoaderDataGraph_lock); + assert_test_pattern(obj, "is_unlocked no_hash", WizardMode); + } + + // WizardMode (not available in release mode) prints details +#ifndef PRODUCT + FlagSetting fs(WizardMode, true); + #endif + HandleMark hm(THREAD); + Handle h_obj(THREAD, obj); + + // Thread tries to lock it. + { + MutexLocker lock(ClassLoaderDataGraph_lock); + ObjectLocker ol(h_obj, THREAD); + assert_test_pattern(obj, "locked"); + assert_test_pattern(obj, "is_unlocked", false); + } + + // Unlocked again + { + MutexLocker lock(ClassLoaderDataGraph_lock); + assert_test_pattern(obj, "is_unlocked"); + } + + // Hash the object then print it. + { + intx hash = h_obj->identity_hash(); + MutexLocker lock(ClassLoaderDataGraph_lock); + assert_test_pattern(obj, "is_unlocked hash="); + } +} + TEST(os, test_random) { const double m = 2147483647; double mean = 0.0, variance = 0.0, t; From 50c49638bdf3a5741e7e906a062d5c85d2230d02 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Wed, 2 Sep 2026 15:36:24 +0000 Subject: [PATCH 206/223] 8295169: Simplify Suspend/Resume and other nsk jvmti tests using checkStatus to sync Reviewed-by: dholmes, sspitsyn, lmesnik --- .../suspendthrd01/libsuspendthrd01.cpp | 132 ------------------ .../suspendthrd01/suspendthrd01.java | 61 +++----- .../jtreg/testlibrary/jvmti/JVMTIUtils.java | 6 +- .../jtreg/testlibrary/jvmti/libJvmtiUtils.cpp | 10 +- 4 files changed, 31 insertions(+), 178 deletions(-) delete mode 100644 test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/libsuspendthrd01.cpp diff --git a/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/libsuspendthrd01.cpp b/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/libsuspendthrd01.cpp deleted file mode 100644 index 053023529cdc..000000000000 --- a/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/libsuspendthrd01.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include "jvmti.h" -#include "jvmti_common.hpp" -#include "jvmti_thread.hpp" - -extern "C" { - -/* ============================================================================= */ - -/* scaffold objects */ -static jlong timeout = 0; - -/* constant names */ -#define THREAD_NAME "TestedThread" - -/* ============================================================================= */ - -/** Agent algorithm. */ -static void JNICALL -agentProc(jvmtiEnv *jvmti, JNIEnv *jni, void *arg) { - - LOG("Wait for thread to start\n"); - if (!agent_wait_for_sync(timeout)) - return; - - /* perform testing */ - { - LOG("Find thread: %s\n", THREAD_NAME); - jthread tested_thread = find_thread_by_name(jvmti, jni, THREAD_NAME); - if (tested_thread == nullptr) { - return; - } - LOG(" ... found thread: %p\n", (void *) tested_thread); - - LOG("Suspend thread: %p\n", (void *) tested_thread); - suspend_thread(jvmti, jni, tested_thread); - - LOG("Let thread to run and finish\n"); - if (!agent_resume_sync()) { - return; - } - - LOG("Get state vector for thread: %p\n", (void *) tested_thread); - { - jint state = get_thread_state(jvmti, jni, tested_thread); - LOG(" ... got state vector: %s (%d)\n", TranslateState(state), (int) state); - - if ((state & JVMTI_THREAD_STATE_SUSPENDED) == 0) { - LOG("SuspendThread() does not turn on flag SUSPENDED:\n" - "# state: %s (%d)\n", TranslateState(state), (int) state); - set_agent_fail_status(); - } - } - - LOG("Resume thread: %p\n", (void *) tested_thread); - resume_thread(jvmti, jni, tested_thread); - - LOG("Wait for thread to finish\n"); - if (!agent_wait_for_sync(timeout)) { - return; - } - - LOG("Delete thread reference\n"); - jni->DeleteGlobalRef(tested_thread); - } - - LOG("Let debugee to finish\n"); - if (!agent_resume_sync()) { - return; - } -} - -/* ============================================================================= */ - -JNIEXPORT jint JNICALL -Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { - jvmtiEnv *jvmti = nullptr; - - timeout = 60 * 1000; - - jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); - if (res != JNI_OK || jvmti == nullptr) { - LOG("Wrong result of a valid call to GetEnv!\n"); - return JNI_ERR; - } - - /* add specific capabilities for suspending thread */ - - jvmtiCapabilities caps; - memset(&caps, 0, sizeof(caps)); - caps.can_suspend = 1; - if (jvmti->AddCapabilities(&caps) != JVMTI_ERROR_NONE) { - return JNI_ERR; - } - - - if (init_agent_data(jvmti, &agent_data) != JVMTI_ERROR_NONE) { - return JNI_ERR; - } - - /* register agent proc and arg */ - if (!set_agent_proc(agentProc, nullptr)) { - return JNI_ERR; - } - - return JNI_OK; -} - -} diff --git a/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java b/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java index 40649965b547..eb505c430bc8 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java +++ b/test/hotspot/jtreg/serviceability/jvmti/thread/SuspendThread/suspendthrd01/suspendthrd01.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,66 +35,39 @@ * Modified due to fix of the RFE * 5001769 TEST_RFE: remove usage of deprecated GetThreadStatus function * - * @library /test/lib - * @run main/othervm/native -agentlib:suspendthrd01=-waittime=5 suspendthrd01 + * @library /test/lib /test/hotspot/jtreg/testlibrary + * @run main/othervm/native suspendthrd01 */ -import jdk.test.lib.jvmti.DebugeeClass; +import jvmti.JVMTIUtils; -public class suspendthrd01 extends DebugeeClass { - - // load native library if required - static { - System.loadLibrary("suspendthrd01"); - } +public class suspendthrd01 { // run test from command line public static void main(String argv[]) { - new suspendthrd01().runIt(argv); - } - - /* =================================================================== */ - - long timeout = 0; - int status = DebugeeClass.TEST_PASSED; - - // run debuggee - public void runIt(String argv[]) { - timeout = 60 * 1000; // milliseconds - - // create tested thread suspendthrd01Thread thread = new suspendthrd01Thread("TestedThread"); - - // run tested thread - System.out.println("Staring tested thread"); + System.out.println("Starting tested thread"); + thread.start(); + if (!thread.checkReady()) { + throw new RuntimeException("Unable to prepare tested thread: " + thread); + } + JVMTIUtils.suspendThread(thread); try { - thread.start(); - if (!thread.checkReady()) { - throw new RuntimeException("Unable to prepare tested thread: " + thread); + // the suspended thread cannot see the flag and must not finish + thread.letFinish(); + int state = JVMTIUtils.getThreadState(thread); + if ((state & JVMTIUtils.JVMTI_THREAD_STATE_SUSPENDED) == 0) { + throw new RuntimeException("Thread is not in the suspended state: " + state); } - - // testing sync - System.out.println("Sync: thread started"); - status = checkStatus(status); } finally { - // let thread to finish - thread.letFinish(); + JVMTIUtils.resumeThread(thread); } - - // wait for thread to finish System.out.println("Finishing tested thread"); try { thread.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } - - // testing sync - System.out.println("Sync: thread finished"); - status = checkStatus(status); - if (checkStatus(status) != 0) { - new RuntimeException(); - } } } diff --git a/test/hotspot/jtreg/testlibrary/jvmti/JVMTIUtils.java b/test/hotspot/jtreg/testlibrary/jvmti/JVMTIUtils.java index b2224b90365c..8833921c41db 100644 --- a/test/hotspot/jtreg/testlibrary/jvmti/JVMTIUtils.java +++ b/test/hotspot/jtreg/testlibrary/jvmti/JVMTIUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ public class JVMTIUtils { public static int JVMTI_ERROR_WRONG_PHASE = 112; + public static int JVMTI_THREAD_STATE_SUSPENDED = 0x100000; + public static class JvmtiException extends RuntimeException { private int code; @@ -82,4 +84,6 @@ public static void resumeThread(Thread t) { } } + public static native int getThreadState(Thread t); + } diff --git a/test/hotspot/jtreg/testlibrary/jvmti/libJvmtiUtils.cpp b/test/hotspot/jtreg/testlibrary/jvmti/libJvmtiUtils.cpp index a5b2b268ff15..610a92f0351d 100644 --- a/test/hotspot/jtreg/testlibrary/jvmti/libJvmtiUtils.cpp +++ b/test/hotspot/jtreg/testlibrary/jvmti/libJvmtiUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,4 +69,12 @@ Java_jvmti_JVMTIUtils_resumeThread0(JNIEnv *jni, jclass cls, jthread thread) { return jvmti->ResumeThread(thread); } +JNIEXPORT jint JNICALL +Java_jvmti_JVMTIUtils_getThreadState(JNIEnv *jni, jclass cls, jthread thread) { + jint state = 0; + jvmtiError err = jvmti->GetThreadState(thread, &state); + check_jvmti_status(jni, err, "Error during GetThreadState()"); + return state; +} + } From 92d7553bd3494a4b2e46d6e6920269f9a58d1edd Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 2 Sep 2026 16:06:56 +0000 Subject: [PATCH 207/223] 8391667: Fix for removed has_no_hash() method Reviewed-by: coleenp --- src/hotspot/share/runtime/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index aaeab6119d3c..34707b22c945 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1345,7 +1345,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { static constexpr uintptr_t valhalla_reserved_bits_in_place = right_n_bits(markWord::valhalla_reserved_bits) << markWord::valhalla_reserved_shift; static constexpr uintptr_t markbits_must_be_zero = valhalla_reserved_bits_in_place | markWord::self_fwd_bit_in_place; - if (mw.has_no_hash() && (mw.value() & markbits_must_be_zero) == 0 && Klass::is_valid(mw.klass_without_asserts())) { + if ((!mw.has_hash()) && (mw.value() & markbits_must_be_zero) == 0 && Klass::is_valid(mw.klass_without_asserts())) { st->print(PTR_FORMAT " looks like a valid markword: ", p2i(addr)); mw.print_on(st); st->print(" "); From 76c862938451488dbed3b2c9f7466f7b8e85ee6f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 2 Sep 2026 17:07:59 +0000 Subject: [PATCH 208/223] 8391062: Shenandoah: Drain overflow queues eagerly Reviewed-by: wkemper, kdnilsen --- .../gc/shenandoah/shenandoahTaskqueue.hpp | 3 +++ .../shenandoah/shenandoahTaskqueue.inline.hpp | 26 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 7bdf2d273498..486a84f204ff 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -62,6 +62,9 @@ class BufferedOverflowTaskQueue: public OverflowTaskQueue return _buf_empty && taskqueue_t::is_empty(); } + NOINLINE + void pop_more_overflow(); + private: bool _buf_empty; E _elem; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp index 0f01425f3e9f..6c070564af00 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2019, Red Hat, Inc. All rights reserved. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,29 @@ bool BufferedOverflowTaskQueue::pop(E &t) { return true; } - return taskqueue_t::pop_overflow(t); + if (taskqueue_t::pop_overflow(t)) { + pop_more_overflow(); + return true; + } + + return false; +} + +template +void BufferedOverflowTaskQueue::pop_more_overflow() { + // Local queue is empty and we have overflow. Overflow queue is invisible + // for work stealing, so we want to transfer as much as practically possible + // from it. Pulling too little hinders work balancing. Pulling too much + // incurs stalls (important e.g. when we need to respond to yield/cancellation). + // Local queues must also have some space left for local pushes. + constexpr uint fill = MIN2(16*K, N/2); + + E tmp; + assert(taskqueue_t::size() == 0, "Local queue is empty"); + for (uint i = 0; (i < fill) && taskqueue_t::pop_overflow(tmp); i++) { + bool pushed = taskqueue_t::try_push_to_taskqueue(tmp); + assert(pushed, "Should always succeed pushing"); + } } template From 4c0c0a568359eee399b75102b72e33f66fc784d1 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 2 Sep 2026 17:41:09 +0000 Subject: [PATCH 209/223] 8391312: GenShen: Avoid testing region affiliation when the region's index is already available Reviewed-by: wkemper, ruili, kdnilsen --- .../shenandoahGenerationalHeuristics.cpp | 10 +++++++-- .../heuristics/shenandoahHeuristics.cpp | 6 +++--- .../heuristics/shenandoahOldHeuristics.cpp | 5 +++-- .../heuristics/shenandoahSpaceInfo.hpp | 2 ++ .../gc/shenandoah/shenandoahGeneration.cpp | 16 +++++++++----- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoahGenerationalControlThread.cpp | 8 ++++--- .../shenandoahGenerationalFullGC.cpp | 8 ++++--- .../share/gc/shenandoah/shenandoahHeap.cpp | 11 ++++++---- .../share/gc/shenandoah/shenandoahHeap.hpp | 4 ++++ .../gc/shenandoah/shenandoahHeap.inline.hpp | 13 ++++++++++++ .../shenandoah/shenandoahMarkingContext.cpp | 6 +++++- .../shenandoah/shenandoahScanRemembered.cpp | 6 +++++- .../gc/shenandoah/shenandoahVerifier.cpp | 21 +++++++++++++++---- 14 files changed, 89 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index dbc795651f22..31f32836ceb3 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -29,6 +29,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahInPlacePromoter.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" @@ -107,9 +108,14 @@ size_t ShenandoahGenerationalHeuristics::prepare_regions_for_promotion(Shenandoa assert_no_in_place_promotions(); size_t candidates = 0; for (size_t i = 0, num_regions = heap->num_regions(); i < num_regions; i++) { + if (!heap->is_region_young(i)) { + // Skip regions that aren't young + continue; + } + ShenandoahHeapRegion* const r = heap->get_region(i); - if (r->is_empty() || !r->has_live() || !r->is_young()) { - // skip over regions that aren't young with some live data + if (r->is_empty() || !r->has_live()) { + // Skip over regions that don't have live data continue; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 410514a3a02d..d0a5d0e0cc10 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -28,6 +28,7 @@ #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahAllocRate.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" @@ -100,12 +101,11 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec size_t free_regions = 0; for (size_t i = 0; i < num_regions; i++) { - ShenandoahHeapRegion* region = heap->get_region(i); - - if (!_space_info->contains(region)) { + if (!_space_info->contains(heap->region_affiliation(i))) { continue; } + ShenandoahHeapRegion* region = heap->get_region(i); size_t garbage = region->garbage(); total_garbage += garbage; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 8d44b2878b6f..1b956b6994a3 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -28,6 +28,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" @@ -413,11 +414,11 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { size_t live_data = 0; RegionData* candidates = _region_data; for (size_t i = 0; i < num_regions; i++) { - ShenandoahHeapRegion* region = heap->get_region(i); - if (!region->is_old()) { + if (!heap->is_region_old(i)) { continue; } + ShenandoahHeapRegion* region = heap->get_region(i); size_t garbage = region->garbage(); size_t live_bytes = region->get_live_data_bytes(); if (!region->was_promoted_in_place()) { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp index 85c5d9fb2fb2..68e297a8273a 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHSPACEINFO_HPP #define SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHSPACEINFO_HPP +#include "gc/shenandoah/shenandoahAffiliation.hpp" #include "utilities/globalDefinitions.hpp" class ShenandoahHeapRegion; @@ -46,6 +47,7 @@ class ShenandoahSpaceInfo { // Return true if this region belongs to this space. virtual bool contains(ShenandoahHeapRegion* region) const = 0; + virtual bool contains(ShenandoahAffiliation affiliation) const = 0; }; #endif //SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHSPACEINFO_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 0068a8574ee7..40463a525ba5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -24,10 +24,12 @@ */ #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" @@ -320,12 +322,16 @@ bool ShenandoahGeneration::is_bitmap_clear() { ShenandoahMarkingContext* context = heap->marking_context(); const size_t num_regions = heap->num_regions(); for (size_t idx = 0; idx < num_regions; idx++) { + const ShenandoahAffiliation affiliation = heap->region_affiliation(idx); + if (!contains(affiliation) || affiliation == FREE) { + // Skip regions outside this generation or those that are unaffiliated + continue; + } + ShenandoahHeapRegion* r = heap->get_region(idx); - if (contains(r) && r->is_affiliated()) { - if (heap->is_bitmap_slice_committed(r) && (context->top_at_mark_start(r) > r->bottom()) && - !context->is_bitmap_range_within_region_clear(r->bottom(), r->end())) { - return false; - } + if (heap->is_bitmap_slice_committed(r) && (context->top_at_mark_start(r) > r->bottom()) && + !context->is_bitmap_range_within_region_clear(r->bottom(), r->end())) { + return false; } } return true; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 9f8944127c00..b58f91e7a7e9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -140,7 +140,7 @@ class ShenandoahGeneration : public CHeapObj, public ShenandoahSpaceInfo { // Cancel marking (used by Full collect and when cancelling cycle). virtual void cancel_marking(); - virtual bool contains(ShenandoahAffiliation affiliation) const = 0; + virtual bool contains(ShenandoahAffiliation affiliation) const override = 0; // Return true if this region is affiliated with this generation. virtual bool contains(ShenandoahHeapRegion* region) const override = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index d03b527a2921..6c3ee675cd0c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -218,10 +218,12 @@ void ShenandoahGenerationalControlThread::maybe_print_young_region_ages() const LogStream ls(lt); AgeTable young_region_ages(false); for (uint i = 0; i < _heap->num_regions(); ++i) { - const ShenandoahHeapRegion* r = _heap->get_region(i); - if (r->is_young()) { - young_region_ages.add(r->age(), r->get_live_data_words()); + if (!_heap->is_region_young(i)) { + continue; } + + const ShenandoahHeapRegion* r = _heap->get_region(i); + young_region_ages.add(r->age(), r->get_live_data_words()); } ls.print("Young regions: "); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 7b59c10b15fe..cfd33994e5fd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -25,6 +25,7 @@ #include "gc/shared/fullGCForwarding.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalFullGC.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" @@ -107,10 +108,11 @@ void ShenandoahGenerationalFullGC::log_live_in_old(ShenandoahHeap* heap) { if (lt.is_enabled()) { size_t live_bytes_in_old = 0; for (size_t i = 0; i < heap->num_regions(); i++) { - ShenandoahHeapRegion* r = heap->get_region(i); - if (r->is_old()) { - live_bytes_in_old += r->get_live_data_bytes(); + if (!heap->is_region_old(i)) { + continue; } + + live_bytes_in_old += heap->get_region(i)->get_live_data_bytes(); } log_debug(gc)("Live bytes in old after STW mark: " PROPERFMT, PROPERFMTARGS(live_bytes_in_old)); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index df06e593d055..0039bda9605b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2498,11 +2498,14 @@ void ShenandoahHeap::assert_pinned_region_status() const { void ShenandoahHeap::assert_pinned_region_status(ShenandoahGeneration* generation) const { for (size_t i = 0; i < num_regions(); i++) { - ShenandoahHeapRegion* r = get_region(i); - if (generation->contains(r)) { - assert((r->is_pinned() && r->pin_count() > 0) || (!r->is_pinned() && r->pin_count() == 0), - "Region %zu pinning status is inconsistent", i); + if (!generation->contains(region_affiliation(i))) { + // Skip regions outside this generation + continue; } + + ShenandoahHeapRegion* r = get_region(i); + assert((r->is_pinned() && r->pin_count() > 0) || (!r->is_pinned() && r->pin_count() == 0), + "Region %zu pinning status is inconsistent", i); } } #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 58ad8f46c058..bf84d60382e9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -654,6 +654,10 @@ class ShenandoahHeap : public CollectedHeap { inline ShenandoahAffiliation region_affiliation(size_t index) const; + inline bool is_region_young(size_t index) const; + inline bool is_region_old(size_t index) const; + inline bool is_region_free(size_t index) const; + bool requires_barriers(stackChunkOop obj) const override; MemRegion reserved_region() const { return _reserved; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index dfd7e722c9ee..55e7f5845aab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -37,6 +37,7 @@ #include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "gc/shared/tlab_globals.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" +#include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" @@ -433,6 +434,18 @@ inline ShenandoahAffiliation ShenandoahHeap::region_affiliation(size_t index) co return (ShenandoahAffiliation) AtomicAccess::load(_affiliations + index); } +inline bool ShenandoahHeap::is_region_young(size_t index) const { + return region_affiliation(index) == YOUNG_GENERATION; +} + +inline bool ShenandoahHeap::is_region_old(size_t index) const { + return region_affiliation(index) == OLD_GENERATION; +} + +inline bool ShenandoahHeap::is_region_free(size_t index) const { + return region_affiliation(index) == FREE; +} + inline bool ShenandoahHeap::requires_marking(const void* entry) const { oop obj = cast_to_oop(entry); return !_marking_context->is_marked_strong(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp index 87629cefb0d4..a23b1a61bce2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp @@ -41,8 +41,12 @@ bool ShenandoahMarkingContext::is_bitmap_clear() const { ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t num_regions = heap->num_regions(); for (size_t idx = 0; idx < num_regions; idx++) { + if (heap->is_region_free(idx)) { + continue; + } + ShenandoahHeapRegion* r = heap->get_region(idx); - if (r->is_affiliated() && heap->is_bitmap_slice_committed(r) + if (heap->is_bitmap_slice_committed(r) && !is_bitmap_range_within_region_clear(r->bottom(), r->end())) { return false; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 103c51db7741..1d7c5919efa1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -630,8 +630,12 @@ void ShenandoahScanRemembered::roots_do(OopIterateClosure* cl) { bool old_bitmap_stable = heap->old_generation()->is_mark_complete(); log_debug(gc, remset)("Scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); for (size_t i = 0, n = heap->num_regions(); i < n; ++i) { + if (!heap->is_region_old(i)) { + continue; + } + ShenandoahHeapRegion* region = heap->get_region(i); - if (region->is_old() && region->is_active() && !region->is_cset()) { + if (region->is_active() && !region->is_cset()) { HeapWord* start_of_range = region->bottom(); HeapWord* end_of_range = region->top(); size_t start_cluster_no = cluster_for_addr(start_of_range); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 19c33c77b26b..be24582de915 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2017, 2025, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ */ #include "gc/shared/tlab_globals.hpp" +#include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahForwarding.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" @@ -1440,8 +1441,12 @@ void ShenandoahVerifier::verify_rem_set_before_mark() { ShenandoahScanRemembered* scanner = old_generation->card_scan(); for (size_t i = 0, n = _heap->num_regions(); i < n; ++i) { + if (!_heap->is_region_old(i)) { + continue; + } + ShenandoahHeapRegion* r = _heap->get_region(i); - if (r->is_old() && r->is_active()) { + if (r->is_active()) { help_verify_region_rem_set(scanner, r, r->end(), "Verify init-mark remembered set violation"); } } @@ -1453,8 +1458,12 @@ void ShenandoahVerifier::verify_rem_set_after_full_gc() { ShenandoahWriteTableScanner scanner(ShenandoahGenerationalHeap::heap()->old_generation()->card_scan()); for (size_t i = 0, n = _heap->num_regions(); i < n; ++i) { + if (!_heap->is_region_old(i)) { + continue; + } + ShenandoahHeapRegion* r = _heap->get_region(i); - if (r->is_old() && !r->is_cset()) { + if (!r->is_cset()) { help_verify_region_rem_set(&scanner, r, r->top(), "Remembered set violation at end of Full GC"); } } @@ -1470,8 +1479,12 @@ void ShenandoahVerifier::verify_rem_set_before_update_ref() { ShenandoahWriteTableScanner scanner(_heap->old_generation()->card_scan()); for (size_t i = 0, n = _heap->num_regions(); i < n; ++i) { + if (!_heap->is_region_old(i)) { + continue; + } + ShenandoahHeapRegion* r = _heap->get_region(i); - if (r->is_old() && !r->is_cset()) { + if (!r->is_cset()) { help_verify_region_rem_set(&scanner, r, r->get_update_watermark(), "Remembered set violation at init-update-references"); } } From 3b34612a97fbe4d37fafa4d5ef6e6fffd85bbff8 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Wed, 2 Sep 2026 17:43:06 +0000 Subject: [PATCH 210/223] 8208250: vmTestbase:metaspace/gc/firstGC* tests are outdated Reviewed-by: coleenp, lmesnik --- test/hotspot/jtreg/ProblemList.txt | 5 - .../gc/metaspace/TestMetaspaceFirstGC.java | 190 +++++++++++++++ .../vmTestbase/metaspace/gc/FirstGCTest.java | 230 ------------------ .../metaspace/gc/HighWaterMarkTest.java | 9 +- .../metaspace/gc/firstGC_10m/TEST.properties | 1 - .../gc/firstGC_10m/TestDescription.java | 44 ---- .../metaspace/gc/firstGC_50m/TEST.properties | 1 - .../gc/firstGC_50m/TestDescription.java | 44 ---- .../metaspace/gc/firstGC_99m/TEST.properties | 1 - .../gc/firstGC_99m/TestDescription.java | 44 ---- .../gc/firstGC_default/TEST.properties | 1 - .../gc/firstGC_default/TestDescription.java | 43 ---- .../jtreg/vmTestbase/metaspace/gc/readme.txt | 6 +- 13 files changed, 198 insertions(+), 421 deletions(-) create mode 100644 test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/FirstGCTest.java delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TestDescription.java diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 89995c8e9658..74759f8bf2eb 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -154,11 +154,6 @@ serviceability/jvmti/RedefineClasses/RedefineRunningMethodsWithBacktrace.java 83 vmTestbase/gc/gctests/FinalizeTest04/FinalizeTest04.java 8284234 generic-all vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java 8284234 generic-all -vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java 8208250 generic-all -vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java 8208250 generic-all -vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java 8208250 generic-all -vmTestbase/metaspace/gc/firstGC_default/TestDescription.java 8208250 generic-all - vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 8073470 linux-all vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t006/TestDescription.java 8372206 generic-all vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all diff --git a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java new file mode 100644 index 000000000000..1bebe7c86d8a --- /dev/null +++ b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestMetaspaceFirstGC + * @bug 8208250 + * @summary Verify that the first metaspace GC happens near the MetaspaceSize threshold + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -Xms200m TestMetaspaceFirstGC + * @run main/othervm -Xms200m -XX:MetaspaceSize=10m TestMetaspaceFirstGC 10m + * @run main/othervm -Xms200m -XX:MetaspaceSize=50m TestMetaspaceFirstGC 50m + * @run main/othervm -Xms200m -XX:MetaspaceSize=99m TestMetaspaceFirstGC 99m + */ + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; +import java.time.Duration; +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +public class TestMetaspaceFirstGC { + + private static int classCounter = 0; + + public interface Dummy {} + + static class DummyHandler implements InvocationHandler { + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + return null; + } + } + + public static void main(String[] args) throws Exception { + long expectedSize = -1; + if (args.length > 0) { + expectedSize = parseSize(args[0]); + } + + try (Recording recording = new Recording()) { + recording.enable(EventNames.GarbageCollection); + recording.enable(EventNames.MetaspaceSummary).withThreshold(Duration.ofMillis(0)); + recording.start(); + + // Load classes until a metaspace-triggered GC happens + loadClassesUntilGC(50000); + + recording.stop(); + + List events = Events.fromRecordingOrdered(recording); + + // Find first GarbageCollection with cause "Metadata GC Threshold" + RecordedEvent gcEvent = null; + for (RecordedEvent event : events) { + if (event.getEventType().getName().equals(EventNames.GarbageCollection)) { + String cause = event.getString("cause"); + if ("Metadata GC Threshold".equals(cause)) { + gcEvent = event; + break; + } + } + } + + if (gcEvent == null) { + throw new RuntimeException("No GC with cause 'Metadata GC Threshold' found"); + } + + int gcId = gcEvent.getInt("gcId"); + System.out.println("Found Metadata GC Threshold GC, gcId=" + gcId); + + // Find matching MetaspaceSummary with same gcId and when="Before GC" + RecordedEvent msEvent = null; + for (RecordedEvent event : events) { + if (event.getEventType().getName().equals(EventNames.MetaspaceSummary)) { + if (event.getInt("gcId") == gcId && "Before GC".equals(event.getString("when"))) { + msEvent = event; + break; + } + } + } + + if (msEvent == null) { + throw new RuntimeException("No MetaspaceSummary 'Before GC' found for gcId=" + gcId); + } + + long committed = msEvent.getLong("metaspace.committed"); + long gcThreshold = msEvent.getLong("gcThreshold"); + System.out.println("MetaspaceSummary: committed=" + committed + " gcThreshold=" + gcThreshold); + + // committed should be reasonably close to gcThreshold + long tolerance = 5 * 1024 * 1024; // 5MB tolerance + Asserts.assertLessThanOrEqual(Math.abs(committed - gcThreshold), tolerance, + "committed (" + committed + ") should be close to gcThreshold (" + gcThreshold + ")"); + + // If explicit MetaspaceSize given, gcThreshold should match it + if (expectedSize > 0) { + Asserts.assertLessThanOrEqual(Math.abs(gcThreshold - expectedSize), tolerance, + "gcThreshold (" + gcThreshold + ") should be close to MetaspaceSize (" + expectedSize + ")"); + System.out.println("gcThreshold matches expected MetaspaceSize=" + expectedSize); + } else { + // No explicit MetaspaceSize — check default range (~12MB to ~20MB per tuning guide) + Asserts.assertGreaterThan(gcThreshold, 11_500_000L, + "default gcThreshold (" + gcThreshold + ") too small"); + Asserts.assertLessThan(gcThreshold, 22_500_000L, + "default gcThreshold (" + gcThreshold + ") too large"); + System.out.println("gcThreshold in expected default range"); + } + + System.out.println("PASSED"); + } + } + + private static void loadClassesUntilGC(int maxIterations) { + long prevUsed = getMetaspaceUsed(); + for (int i = 0; i < maxIterations; i++) { + loadOneClass(); + long used = getMetaspaceUsed(); + if (used < prevUsed) { + System.out.println("GC detected at iteration " + i + + ", used dropped from " + prevUsed + " to " + used); + return; + } + prevUsed = used; + } + throw new RuntimeException("No metaspace GC after " + maxIterations + " class loads"); + } + + private static void loadOneClass() { + try { + String jarUrl = "file:" + (classCounter++) + ".jar"; + URLClassLoader cl = new URLClassLoader(new URL[]{new URL(jarUrl)}); + Proxy.newProxyInstance(cl, new Class[]{Dummy.class}, new DummyHandler()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static long getMetaspaceUsed() { + return java.lang.management.ManagementFactory.getMemoryPoolMXBeans().stream() + .filter(p -> p.getName().equals("Metaspace")) + .mapToLong(p -> p.getUsage().getUsed()) + .findFirst() + .orElseThrow(() -> new RuntimeException("Metaspace pool not found")); + } + + private static long parseSize(String size) { + size = size.toLowerCase(); + long multiplier = 1; + if (size.endsWith("m")) { + multiplier = 1024 * 1024; + size = size.substring(0, size.length() - 1); + } else if (size.endsWith("k")) { + multiplier = 1024; + size = size.substring(0, size.length() - 1); + } else if (size.endsWith("g")) { + multiplier = 1024 * 1024 * 1024; + size = size.substring(0, size.length() - 1); + } + return Long.parseLong(size) * multiplier; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/FirstGCTest.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/FirstGCTest.java deleted file mode 100644 index 517a2066d641..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/FirstGCTest.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package metaspace.gc; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import static metaspace.gc.MetaspaceBaseGC.PAGE_SIZE; - -/** - * Test for metaspace GC - * - *

        - *
      • MetaspaceSize - *
      - * Test checks that the first GC happens when metaspace committed is next to - * MetaspaceSize value. - * - * Based on actual events (JDK 8 GC tuning document) - * - * Quating: Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning - *
      - * Class metadata is deallocated when the corresponding Java class is unloaded.
      - * Java classes are unloaded as a results of garbage collection and garbage
      - * collections may be induced in order to unload classes and deallocate class
      - * metadata. When the space used for class metadata reaches a certain level
      - * (call it a high-water mark), a garbage collection is induced.
      - *
      - * The flag MetaspaceSize can be set higher to avoid early garbage collections
      - * induced for class metadata. The amount of class metadata allocated for
      - * an application is application dependent and general guidelines do not
      - * exist for the selection of MetaspaceSize. The default size of MetaspaceSize
      - * is platform dependent and ranges from 12 MB to about 20 MB.
      - * 
      - */ -public class FirstGCTest extends MetaspaceBaseGC { - /** - * Current amount of the used metaspace - */ - protected long used = 0; - - /** - * Current amount of the committed metaspace - */ - protected long committed = 0; - - /** - * Previous amount of the used metaspace - */ - protected long p_used = 0 ; - - /** - * Previous amount of the committed metaspace - */ - protected long p_committed = 0; - - public static void main(String... args) { - new FirstGCTest().run(args); - } - - // value given in -XX:metaspaceSize= - private long metaspaceSize = -1; - - - @Override - protected void parseArgs(String[] args) { - final String XXSize = "-XX:MetaspaceSize="; - for (String va: vmArgs) { - if (va.startsWith(XXSize)) { - metaspaceSize = parseValue(va.substring(XXSize.length())); - } - } - } - - @Override - protected String getPoolName() { - return "Metaspace"; - } - - /** - * Check for the first GC moment. - * - * Eats memory until GC is invoked (amount of used metaspace became less); - * Checks that committed memory is close to MemaspaceSize. - * Eats memory until the second GC to check min/max ratio options have effect. - */ - @Override - public void doCheck() { - int gcCount = super.getMetaspaceGCCount(); - if (gcCount == 0) { - // gc hasn't happened yet. Start loading classes. - boolean gcHappened = this.eatMemoryUntilGC(50000); - if (!gcHappened) { - throw new Fault("GC hasn't happened"); - } - System.out.println("% GC: " + super.lastGCLogLine()); - System.out.println("% used : " + p_used + " --> " + used); - System.out.println("% committed: " + p_committed + " --> " + committed); - checkCommitted(p_committed); - } else { - // everything has happened before - checkCommitted(detectCommittedFromGCLog()); - } - } - - /** - * Check that committed amount is close to expected value (MetaspaceSize) - * - * @param committedAmount - value to check - */ - void checkCommitted(long committedAmount) { - if (metaspaceSize > 0) { - // -XX:MetaspaceSize is given - if (Math.abs((int) (metaspaceSize - committedAmount)) < PAGE_SIZE) { - System.out.println("% GC happened at the right moment"); - return; - } - if (!isMetaspaceGC()) { - System.out.println("% GC wasn't induced by metaspace, cannot check the moment :("); - return; - } - System.err.println("%## GC happened at the wrong moment, " - + "the amount of committed space significantly differs " - + "from the expected amount"); - System.err.println("%## Real : " + committedAmount); - System.err.println("%## Expected: " + metaspaceSize); - throw new Fault("GC happened at the wrong moment"); - } else { - // -XX:MetaspaceSize is not given, check for default values - if (11_500_000 < committedAmount && committedAmount < 22_500_000) { - System.out.println("% GC happened when the committed amout was from 12 MB to about 20 MB."); - return; - } - if (!isMetaspaceGC()) { - System.out.println("% GC wasn't induced by metaspace, this is excuse"); - return; - } - System.err.println("%## GC happened at the wrong moment, " - + "the amount of committed space was expected from 12 MB to about 20 MB"); - System.err.println("%## Real : " + committedAmount); - throw new Fault("It was the wrong moment when GC happened"); - } - } - - /** - * Load new classes without keeping references to them trying to provoke GC. - * Stops if GC is detected, or number of attempts exceeds the given limit. - * - * @param times limit of attempts to provoke GC - * @return true if GC has happened, false if limit has exceeded. - */ - protected boolean eatMemoryUntilGC(int times) { - System.out.println("%%%% Loading classes"); - System.out.println("% iter# : used : commited"); - System.out.println(".............................."); - for (int i = 1; i < times; i++) { - loadNewClasses(1, false); - if (i % 1000 == 0) { - printMemoryUsage("% " + i + " "); - } - p_used = used; - p_committed = committed; - used = getUsed(); - committed = getCommitted(); - - if (used < p_used) { - return true; - } - } - return false; - } - - /** - * If the first full GC has already happened we will try to detect - * the committed amount from the gc.log file. - * - * @return committed amount detected - * @throws Fault if failed to detect. - */ - protected long detectCommittedFromGCLog() { - // parse gc.log to extract the committed value from string like: - // Metaspace used 10133K, capacity 10190K, committed 10240K, reserved 10240Kl - System.out.println("%%%% Parsing gc log to detect the moment of the first GC"); - String format = ".*Metaspace.* used .*, capacity .*, committed (\\d+)([KMGkmg]), reserved .*"; - Pattern p = Pattern.compile(format); - try { - for (String line: readGCLog()) { - Matcher m = p.matcher(line); - if (m.matches()) { - int amount = Integer.parseInt(m.group(1)); - int multi = 1; - switch (m.group(2).toLowerCase()) { - case "k": multi = 1024; break; - case "m": multi = 1024*1024; break; - case "g": multi = 1024*1024*1024; break; - } - long value = amount * multi; - System.out.println("% Committed detected: " + value); - return value; - } - } - } catch (IOException e) { - throw new Fault("Cannot read from the GC log"); - } - System.out.println("% String that matches pattern '" + format + "' not found in the GC log file."); - throw new Fault("Unable to detect the moment of GC from log file"); - } - -} diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/HighWaterMarkTest.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/HighWaterMarkTest.java index 244431100f7b..e819247a7a2e 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/HighWaterMarkTest.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/HighWaterMarkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,12 @@ * If it is less than MinMetaspaceFreeRatio, the high-water mark will be raised. * */ -public class HighWaterMarkTest extends FirstGCTest { +public class HighWaterMarkTest extends MetaspaceBaseGC { + + @Override + protected String getPoolName() { + return "Metaspace"; + } public static void main(String... args) { new HighWaterMarkTest().run(args); diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TEST.properties b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TEST.properties deleted file mode 100644 index 3d748e1ab1f7..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TEST.properties +++ /dev/null @@ -1 +0,0 @@ -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java deleted file mode 100644 index f445f538ea79..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @modules java.base/jdk.internal.misc:+open - * - * @summary converted from VM Testbase metaspace/gc/firstGC_10m. - * VM Testbase keywords: [nonconcurrent, quarantine] - * VM Testbase comments: 8208250 - * - * @library /vmTestbase /test/lib - * @run main/othervm - * -Xms200m - * -Xlog:gc+heap=trace,gc:gc.log - * -XX:MetaspaceSize=10m - * -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions - * -XX:-VerifyBeforeExit - * -XX:-UseCompressedOops - * metaspace.gc.FirstGCTest - */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TEST.properties b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TEST.properties deleted file mode 100644 index 3d748e1ab1f7..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TEST.properties +++ /dev/null @@ -1 +0,0 @@ -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java deleted file mode 100644 index 6df788cf3548..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @modules java.base/jdk.internal.misc:+open - * - * @summary converted from VM Testbase metaspace/gc/firstGC_50m. - * VM Testbase keywords: [nonconcurrent, quarantine] - * VM Testbase comments: 8208250 - * - * @library /vmTestbase /test/lib - * @run main/othervm - * -Xms200m - * -Xlog:gc+heap=trace,gc:gc.log - * -XX:MetaspaceSize=50m - * -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions - * -XX:-VerifyBeforeExit - * -XX:-UseCompressedOops - * metaspace.gc.FirstGCTest - */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TEST.properties b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TEST.properties deleted file mode 100644 index 3d748e1ab1f7..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TEST.properties +++ /dev/null @@ -1 +0,0 @@ -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java deleted file mode 100644 index fe8777eed862..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @modules java.base/jdk.internal.misc:+open - * - * @summary converted from VM Testbase metaspace/gc/firstGC_99m. - * VM Testbase keywords: [nonconcurrent, quarantine] - * VM Testbase comments: 8208250 - * - * @library /vmTestbase /test/lib - * @run main/othervm - * -Xms200m - * -Xlog:gc+heap=trace,gc:gc.log - * -XX:MetaspaceSize=99m - * -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions - * -XX:-VerifyBeforeExit - * -XX:-UseCompressedOops - * metaspace.gc.FirstGCTest - */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TEST.properties b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TEST.properties deleted file mode 100644 index 3d748e1ab1f7..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TEST.properties +++ /dev/null @@ -1 +0,0 @@ -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TestDescription.java deleted file mode 100644 index 556dcd28c8d2..000000000000 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/firstGC_default/TestDescription.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - * @test - * @modules java.base/jdk.internal.misc:+open - * - * @summary converted from VM Testbase metaspace/gc/firstGC_default. - * VM Testbase keywords: [nonconcurrent, quarantine] - * VM Testbase comments: 8208250 - * - * @library /vmTestbase /test/lib - * @run main/othervm - * -Xms200m - * -Xlog:gc+heap=trace,gc:gc.log - * -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions - * -XX:-VerifyBeforeExit - * -XX:-UseCompressedOops - * metaspace.gc.FirstGCTest - */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/readme.txt b/test/hotspot/jtreg/vmTestbase/metaspace/gc/readme.txt index b1f337d251ca..214a6c0ff35a 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/readme.txt +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/readme.txt @@ -25,16 +25,12 @@ metaspace/gc tests - are the test for the Metaspace GC tuning, which is describe Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning Tests load classes and monitor the used/committed amounts of metaspace. -There are three types of tests all extending base class - MetaspaceBaseGC +There are two types of tests all extending base class - MetaspaceBaseGC MemoryUsageTest - trivial test to check memory dynamic (loading classes should lead to growth of used memory, gc to reduce) -FirstGCTest - - loads classes until the GC has happened and check the GC has happened at the - right moment (as stated in the Spec) - HighWaterMarkTest The test loads classes until the committed metaspace achieves the certain level between MetaspaceSize and MaxMetaspaceSize. From 702f6d3a2ba445bc2de5f12d8d2c8e6df8f43706 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 2 Sep 2026 18:24:13 +0000 Subject: [PATCH 211/223] 8391488: GenShen: Remembered set scan should use compact-object-header aware accessors Reviewed-by: shade, ruili --- .../gc/shenandoah/shenandoahScanRemembered.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 1d7c5919efa1..57899154ff73 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -226,7 +226,7 @@ void ShenandoahCardCluster::update_card_table(HeapWord* start, HeapWord* end) { previous_address = address; const oop obj = cast_to_oop(address); - address += obj->size(); + address += ShenandoahForwarding::size(obj); } // Register the last object seen in this range. @@ -345,7 +345,7 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con if (prev < left) { oop obj = cast_to_oop(prev); assert(oopDesc::is_oop(obj), "Should be an object"); - HeapWord* obj_end = prev + obj->size(); + HeapWord* obj_end = prev + ShenandoahForwarding::size(obj); if (obj_end > left) { return prev; } @@ -397,7 +397,7 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con if (ctx->is_marked(p)) { oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - assert(p + obj->size() > left, "This object should span start of card"); + assert(p + ShenandoahForwarding::size(obj) > left, "This object should span start of card"); assert(p < right, "Result must precede right"); return p; } else { @@ -443,7 +443,7 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con #ifdef ASSERT oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - assert(p + obj->size() > left, "obj should end after left end of card"); + assert(p + ShenandoahForwarding::size(obj) > left, "obj should end after left end of card"); #endif // ASSERT return p; } @@ -514,7 +514,7 @@ bool ShenandoahScanRemembered::verify_registration(HeapWord* address, Shenandoah while (base_addr + offset < address) { oop obj = cast_to_oop(base_addr + offset); if (!ctx || ctx->is_marked(obj)) { - offset += obj->size(); + offset += ShenandoahForwarding::size(obj); } else { // If this object is not live, don't trust its size(); all objects above tams are live. ShenandoahHeapRegion* r = heap->heap_region_containing(obj); @@ -543,7 +543,7 @@ bool ShenandoahScanRemembered::verify_registration(HeapWord* address, Shenandoah do { oop obj = cast_to_oop(base_addr + offset); prev_offset = offset; - offset += obj->size(); + offset += ShenandoahForwarding::size(obj); } while (offset < max_offset); if (_scc->get_last_start(index) != prev_offset) { return false; @@ -582,7 +582,7 @@ bool ShenandoahScanRemembered::verify_registration(HeapWord* address, Shenandoah oop obj = cast_to_oop(base_addr + offset); if (ctx->is_marked(obj)) { prev_offset = offset; - offset += obj->size(); + offset += ShenandoahForwarding::size(obj); last_obj = obj; } else { offset = ctx->get_next_marked_addr(base_addr + offset, tams) - base_addr; @@ -592,7 +592,7 @@ bool ShenandoahScanRemembered::verify_registration(HeapWord* address, Shenandoah // by consulting the size() fields of each. } } while (offset < max_offset); - if (last_obj != nullptr && prev_offset + last_obj->size() >= max_offset) { + if (last_obj != nullptr && prev_offset + ShenandoahForwarding::size(last_obj) >= max_offset) { // last marked object extends beyond end of card if (_scc->get_last_start(index) != prev_offset) { return false; @@ -1078,7 +1078,7 @@ void ShenandoahReconstructRememberedSetTask::work(uint worker_id) { if (r->is_humongous_start()) { // First, clear the remembered set oop obj = cast_to_oop(obj_addr); - size_t size = obj->size(); + size_t size = ShenandoahForwarding::size(obj); size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); size_t region_index = r->index(); From edb410c4668edc0db50607ec646471246c3fbbd5 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 2 Sep 2026 18:30:04 +0000 Subject: [PATCH 212/223] 8391683: Gtest failure with markWord is_unlocked Reviewed-by: fparain, dcubed --- test/hotspot/gtest/runtime/test_os.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 17eb611bbd8b..3cfbb1185601 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -132,7 +132,7 @@ TEST_VM(os, test_print_markword) { markWord m0 = vmClasses::Byte_klass()->prototype_header(); const struct { markWord mw; const char* expected; } patterns[] = { { markWord(0), "is null"}, - { m0, "mark(is_unlocked no_hash age=0) java.lang.Byte" }, + { m0, "mark(is_lock_neutral no_hash age=0) java.lang.Byte" }, { m0.set_age(2), "age=2" }, { m0.copy_set_hash(0x12345), "is an unknown value" } }; @@ -167,7 +167,7 @@ TEST_VM(os, test_print_location) { { // wizard mode off, so don't print markword MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_unlocked no_hash", WizardMode); + assert_test_pattern(obj, "is_lock_neutral no_hash", WizardMode); } // WizardMode (not available in release mode) prints details @@ -182,20 +182,20 @@ TEST_VM(os, test_print_location) { MutexLocker lock(ClassLoaderDataGraph_lock); ObjectLocker ol(h_obj, THREAD); assert_test_pattern(obj, "locked"); - assert_test_pattern(obj, "is_unlocked", false); + assert_test_pattern(obj, "is_lock_neutral", false); } // Unlocked again { MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_unlocked"); + assert_test_pattern(obj, "is_lock_neutral"); } // Hash the object then print it. { intx hash = h_obj->identity_hash(); MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_unlocked hash="); + assert_test_pattern(obj, "is_lock_neutral hash="); } } From 2d02c8eaaccd12acd2101ea2986f406f67f55eef Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Wed, 2 Sep 2026 20:28:05 +0000 Subject: [PATCH 213/223] 8370245: Change default PKCS12 mac algorithm to PBMAC1 Reviewed-by: mullan, weijun --- .../sun/security/pkcs12/PKCS12KeyStore.java | 2 +- .../share/conf/security/java.security | 4 +- .../pkcs11/KeyStore/ImportKeyToP12.java | 37 +++++++++++++-- .../pkcs12/KeytoolOpensslInteropTest.java | 30 ++++++------- .../security/pkcs12/ParamsPreferences.java | 45 +++++++++++++++---- .../bench/java/security/PKCS12KeyStores.java | 18 +++++--- 6 files changed, 101 insertions(+), 35 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index c7240b54ebdc..7c9d306b78ec 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -83,7 +83,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { = "PBEWithHmacSHA256AndAES_256"; private static final String DEFAULT_KEY_PBE_ALGORITHM = "PBEWithHmacSHA256AndAES_256"; - private static final String DEFAULT_MAC_ALGORITHM = "HmacPBESHA256"; + private static final String DEFAULT_MAC_ALGORITHM = "PBEWithHmacSHA256"; private static final int DEFAULT_CERT_PBE_ITERATION_COUNT = 10000; private static final int DEFAULT_KEY_PBE_ITERATION_COUNT = 10000; private static final int DEFAULT_MAC_ITERATION_COUNT = 10000; diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 7f806ed2cf5f..4289254affcf 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1373,8 +1373,8 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # file. This can be any HmacPBE or PBEWith algorithm defined in # the Mac section of the Java Security Standard Algorithm Names Specification, # for example, HmacPBESHA256 or PBEWithHmacSHA256. When set to "NONE", -# no Mac is generated. The default value is "HmacPBESHA256". -#keystore.pkcs12.macAlgorithm = HmacPBESHA256 +# no Mac is generated. The default value is "PBEWithHmacSHA256". +#keystore.pkcs12.macAlgorithm = PBEWithHmacSHA256 # The iteration count used by the MacData algorithm. This value must be a # positive integer. The default value is 10000. diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java index 0e8cb36659f8..27a1073e4a40 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -33,6 +34,9 @@ import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; /* @@ -60,7 +64,9 @@ public final class ImportKeyToP12 extends PKCS11Test { }; private static final String[] pbeMacAlgs = new String[] { "HmacPBESHA1", "HmacPBESHA224", "HmacPBESHA256", - "HmacPBESHA384", "HmacPBESHA512" + "HmacPBESHA384", "HmacPBESHA512", "PBEWithHmacSHA1", + "PBEWithHmacSHA224", "PBEWithHmacSHA256", "PBEWithHmacSHA384", + "PBEWithHmacSHA512" }; private static final KeyStore p12; private static final String sep = "======================================" + @@ -74,6 +80,14 @@ public final class ImportKeyToP12 extends PKCS11Test { p12 = tP12; } + private record PBMAC1Algorithms(String pbkdf2, String hmac) {} + + private static PBMAC1Algorithms pbmac1Algorithms(String algorithm) { + // PBMAC1 algorithms with matching PBKDF2 PRF and HMAC names. + String hmac = algorithm.substring("PBEWith".length()); + return new PBMAC1Algorithms("PBKDF2With" + hmac, hmac); + } + public void main(Provider sunPKCS11) throws Exception { System.out.println("SunPKCS11: " + sunPKCS11.getName()); // Test all privacy PBE algorithms with an integrity algorithm fixed @@ -84,8 +98,25 @@ public void main(Provider sunPKCS11) throws Exception { } // Test all integrity PBE algorithms with a privacy algorithm fixed for (String pbeMacAlg : pbeMacAlgs) { - // Make sure that SunPKCS11 implements the Mac algorithm - Mac.getInstance(pbeMacAlg, sunPKCS11); + // Verify the PBKDF2/HMAC components needed for PBMAC1 are present + if (pbeMacAlg.startsWith("PBEWith")) { + byte[] salt = { 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 }; + + PBMAC1Algorithms algorithms = pbmac1Algorithms(pbeMacAlg); + Mac m = Mac.getInstance(algorithms.hmac(), sunPKCS11); + int keyLength = m.getMacLength() * Byte.SIZE; + SecretKeyFactory skf = SecretKeyFactory.getInstance( + algorithms.pbkdf2(), sunPKCS11); + PBEKeySpec keySpec = new PBEKeySpec(password, + salt, 10000, keyLength); + + SecretKey pbeKey = skf.generateSecret(keySpec); + m.init(pbeKey); + m.doFinal(); + } else { + Mac.getInstance(pbeMacAlg, sunPKCS11); + } testWith(sunPKCS11, pbeCipherAlgs[0], pbeMacAlg); } System.out.println("TEST PASS - OK"); diff --git a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java index eee55998f0bc..c29f7a0b11db 100644 --- a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java +++ b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -182,8 +182,8 @@ private static void testWithJavaCommands() throws Throwable { + "-destkeystore ksnormal -deststorepass changeit"); data = Files.readAllBytes(Path.of("ksnormal")); - checkInt(data, "22", 10000); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 10000); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 10000); // key ic checkAlg(data, "110c10", ENCRYPTED_DATA_OID); @@ -210,8 +210,8 @@ private static void testWithJavaCommands() throws Throwable { + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " + "-J-Dkeystore.pkcs12.macAlgorithm=NONE"); data = Files.readAllBytes(Path.of("ksnormal")); - checkInt(data, "22", 10000); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 10000); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 10000); // key ic checkAlg(data, "110c010c11000", PBES2); // new key alg @@ -255,8 +255,8 @@ private static void testWithJavaCommands() throws Throwable { + "-J-Dkeystore.pkcs12.certPbeIterationCount=6666 " + "-J-Dkeystore.pkcs12.keyPbeIterationCount=7777"); data = Files.readAllBytes(Path.of("ksnewic")); - checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 5555); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 7777); // key ic checkAlg(data, "110c110110", PBES2); // cert alg @@ -274,8 +274,8 @@ private static void testWithJavaCommands() throws Throwable { + "-storepass changeit -alias b -dname CN=B " + "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128"); data = Files.readAllBytes(Path.of("ksnewic")); - checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 5555); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 7777); // key ic checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg @@ -291,8 +291,8 @@ private static void testWithJavaCommands() throws Throwable { ks.store(fos, "changeit".toCharArray()); } data = Files.readAllBytes(Path.of("ksnormaldup")); - checkInt(data, "22", 10000); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 10000); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 10000); // key ic checkAlg(data, "110c010c11000", PBES2); // new key alg @@ -320,8 +320,8 @@ private static void testWithJavaCommands() throws Throwable { ks.store(fos, "changeit".toCharArray()); } data = Files.readAllBytes(Path.of("ksnewicdup")); - checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", SHA_256); // Mac alg + checkInt(data, "2001011", 5555); // Mac ic + checkAlg(data, "2000", PBMAC1); // Mac alg checkAlg(data, "110c010c01000", PBES2); // key alg checkInt(data, "110c010c01001011", 7777); // key ic checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg @@ -476,7 +476,7 @@ private static void testWithOpensslCommands(String opensslPath) "pkcs12", "-in", "ksnormal", "-passin", "pass:changeit", "-info", "-nokeys", "-nocerts"); output1.shouldHaveExitValue(0) - .shouldMatch("MAC:.*sha256.*Iteration 10000") + .shouldMatch("MAC:.*PBMAC1.*Iteration 10000") .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," + " Iteration 10000, PRF hmacWithSHA256") .shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC," @@ -521,7 +521,7 @@ private static void testWithOpensslCommands(String opensslPath) "ksnewic", "-passin", "pass:changeit", "-info", "-nokeys", "-nocerts"); output1.shouldHaveExitValue(0) - .shouldMatch("MAC:.*sha256.*Iteration 5555") + .shouldMatch("MAC:.*PBMAC1.*Iteration 5555") .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," + " Iteration 7777, PRF hmacWithSHA256") .shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4," diff --git a/test/jdk/sun/security/pkcs12/ParamsPreferences.java b/test/jdk/sun/security/pkcs12/ParamsPreferences.java index c40bd4f4b705..47b1e07891e5 100644 --- a/test/jdk/sun/security/pkcs12/ParamsPreferences.java +++ b/test/jdk/sun/security/pkcs12/ParamsPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ public static final void main(String[] args) throws Exception { Map.of(), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, - SHA_256, 10000); + PBMAC1, 10000); // legacy settings test(c++, @@ -116,7 +116,33 @@ public static final void main(String[] args) throws Exception { "keystore.pkcs12.macAlgorithm", "NONE"), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, - SHA_256, 10000); + PBMAC1, 10000); + + // configure PBMAC1 MAC with system property + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "PBEWithHmacSHA256", + "keystore.pkcs12.macIterationCount", 2000), + Map.of(), + PBEWithSHA1AndDESede, 3000, + PBEWithSHA1AndRC2_40, 4000, + PBMAC1, 2000); + + // configure PBMAC1 MAC with security property + test(c++, + Map.of(), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "PBEWithHmacSHA256", + "keystore.pkcs12.macIterationCount", 2000), + PBEWithSHA1AndDESede, 3000, + PBEWithSHA1AndRC2_40, 4000, + PBMAC1, 2000); // change everything with system property test(c++, @@ -170,21 +196,21 @@ public static final void main(String[] args) throws Exception { Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128"), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBEWithSHA1AndRC2_128, 10000, - SHA_256, 10000); + PBMAC1, 10000); test(c++, Map.of(), Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBEWithSHA1AndRC2_40, 10000, - SHA_256, 10000); + PBMAC1, 10000); test(c++, Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128"), Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBEWithSHA1AndRC4_128, 10000, - SHA_256, 10000); + PBMAC1, 10000); test(c++, Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128", "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_40"), @@ -192,7 +218,7 @@ public static final void main(String[] args) throws Exception { "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, PBEWithSHA1AndRC4_40, 10000, - SHA_256, 10000); + PBMAC1, 10000); // 8266293 test(c++, @@ -201,7 +227,7 @@ public static final void main(String[] args) throws Exception { Map.of(), PBEWithMD5AndDES, 10000, PBEWithMD5AndDES, 10000, - SHA_256, 10000); + PBMAC1, 10000); } /** @@ -269,6 +295,9 @@ static void test(int n, Map sysProps, KnownOIDs macAlg = (KnownOIDs)args[i++]; if (macAlg == null) { shouldNotExist(data, "2"); + } else if (macAlg.stdName().equals("PBMAC1")) { + checkAlg(data, "2000", macAlg); + checkInt(data, "2001011", (int) args[i++]); } else { checkAlg(data, "2000", macAlg); checkInt(data, "22", (int) args[i++]); diff --git a/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java b/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java index d5da132e5f14..5770fb8a7aac 100644 --- a/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java +++ b/test/micro/org/openjdk/bench/java/security/PKCS12KeyStores.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,12 @@ @BenchmarkMode(Mode.AverageTime) @Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) public class PKCS12KeyStores { + @Param({"false", "true"}) + private boolean pbmac1; + + private String macAlgorithm(String legacyAlgorithm) { + return pbmac1 ? "PBEWithHmacSHA256" : legacyAlgorithm; + } private static final char[] PASS = "changeit".toCharArray(); @@ -151,14 +157,14 @@ public KeyStore instrong2048() throws Exception { public byte[] outweak2048() throws Exception { return out("PBEWithSHA1AndRC2_40", "2048", "PBEWithSHA1AndDESede", "2048", - "HmacPBESHA1", "2048"); + macAlgorithm("HmacPBESHA1"), "2048"); } @Benchmark public byte[] outweak50000_Old() throws Exception { return out("PBEWithSHA1AndRC2_40", "50000", "PBEWithSHA1AndDESede", "50000", - "HmacPBESHA1", "100000"); + macAlgorithm("HmacPBESHA1"), "100000"); // Attention: 100000 is old default Mac ic } @@ -166,7 +172,7 @@ public byte[] outweak50000_Old() throws Exception { public byte[] outstrong50000() throws Exception { return out("PBEWithHmacSHA256AndAES_256", "50000", "PBEWithHmacSHA256AndAES_256", "50000", - "HmacPBESHA256", "100000"); + macAlgorithm("HmacPBESHA256"), "100000"); // Attention: 100000 is old default Mac ic } @@ -174,13 +180,13 @@ public byte[] outstrong50000() throws Exception { public byte[] outstrong10000_New() throws Exception { return out("PBEWithHmacSHA256AndAES_256", "10000", "PBEWithHmacSHA256AndAES_256", "10000", - "HmacPBESHA256", "10000"); + macAlgorithm("HmacPBESHA256"), "10000"); } @Benchmark public byte[] outstrong2048() throws Exception { return out("PBEWithHmacSHA256AndAES_256", "2048", "PBEWithHmacSHA256AndAES_256", "2048", - "HmacPBESHA256", "2048"); + macAlgorithm("HmacPBESHA256"), "2048"); } } From 604bab356c6863a6cca6435242b711eb10e5ef7d Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 2 Sep 2026 20:32:39 +0000 Subject: [PATCH 214/223] 8391496: nmethod copy constructor incorrectly clears _oops_do_mark_nmethods Reviewed-by: tschatzl, eosterlund, eastigeevich --- src/hotspot/share/code/nmethod.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c36582f73813..30cd400058b5 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1388,7 +1388,6 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. _exception_cache = nullptr; _gc_data = nullptr; - _oops_do_mark_nmethods = nullptr; _oops_do_mark_link = nullptr; _compiled_ic_data = nullptr; From 5edeb1620cfed06b2cab1f4e31f4f1e2b648a44d Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Wed, 2 Sep 2026 21:00:09 +0000 Subject: [PATCH 215/223] 8380847: Versioned class loaded from multi-release jar file is not cached Reviewed-by: iklam, alanb, coleenp --- src/hotspot/share/cds/aotClassLocation.cpp | 25 ++++- src/hotspot/share/cds/aotClassLocation.hpp | 1 + src/hotspot/share/classfile/classLoader.cpp | 56 +++++++++-- src/hotspot/share/classfile/classLoader.hpp | 2 +- src/hotspot/share/classfile/vmClassMacros.hpp | 1 + src/hotspot/share/classfile/vmSymbols.hpp | 2 + .../share/classes/jdk/internal/misc/CDS.java | 28 +++++- .../runtime/cds/appcds/MultiReleaseJars.java | 96 ++++++++++++++++++- 8 files changed, 192 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 48b91960ce77..e33d4b6ff24e 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -39,8 +39,10 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/array.hpp" +#include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "runtime/arguments.hpp" +#include "runtime/handles.inline.hpp" #include "utilities/classpathStream.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/stringUtils.hpp" @@ -279,7 +281,8 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa } assert(*(cs->manifest() + cs->manifest_length()) == '\0', "should be nul-terminated"); - if (strstr(cs->manifest(), "Multi-Release: true") != nullptr) { + const char* multi_release = cs->get_attr("Multi-Release: "); + if (multi_release != nullptr && strcasecmp(multi_release, "true") == 0) { cs->_is_multi_release_jar = true; } @@ -321,7 +324,7 @@ char* AOTClassLocation::read_manifest(JavaThread* current, const char* path, siz } // The result is resource allocated. -char* AOTClassLocation::get_cpattr() const { +char* AOTClassLocation::get_attr(const char* tag) const { if (_manifest_length == 0) { return nullptr; } @@ -337,7 +340,6 @@ char* AOTClassLocation::get_cpattr() const { // Remove all new-line continuation (remove all "\n " substrings) StringUtils::replace_no_expand(buf, "\n ", ""); - const char* tag = "Class-Path: "; size_t tag_len = strlen(tag); char* found = nullptr; char* line_start = buf; @@ -351,7 +353,13 @@ char* AOTClassLocation::get_cpattr() const { // JAR spec require the manifest file to be terminated by a new line. break; } - if (strncmp(tag, line_start, tag_len) == 0) { + + if (line_start == line_end) { + break; + } + + // Attribute names are case insensitive + if (strncasecmp(tag, line_start, tag_len) == 0) { if (found != nullptr) { // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java // If duplicated entries are found, the last one is used. @@ -370,6 +378,11 @@ char* AOTClassLocation::get_cpattr() const { return found; } +// The result is resource allocated. +char* AOTClassLocation::get_cpattr() const { + return get_attr("Class-Path: "); +} + AOTClassLocation* AOTClassLocation::write_to_archive() const { AOTClassLocation* archived_copy = (AOTClassLocation*)ArchiveBuilder::ro_region_alloc(total_size()); memcpy((char*)archived_copy, (char*)this, total_size()); @@ -719,7 +732,9 @@ bool AOTClassLocationConfig::is_valid_classpath_index(int classpath_index, Insta const char* const class_name = ik->name()->as_C_string(); const char* const file_name = ClassLoader::file_name_for_class_name(class_name, ik->name()->utf8_length()); - if (!zip->has_entry(current, file_name)) { + Handle class_loader(current, ik->class_loader()); + const AOTClassLocation* cl = AOTClassLocationConfig::class_location_at(classpath_index); + if (!zip->has_entry(current, file_name, class_loader, cl->is_multi_release_jar())) { aot_log_warning(aot)("class %s cannot be archived because it was not defined from %s as claimed", class_name, zip->name()); return false; diff --git a/src/hotspot/share/cds/aotClassLocation.hpp b/src/hotspot/share/cds/aotClassLocation.hpp index 771f4951671c..9a64e0deffae 100644 --- a/src/hotspot/share/cds/aotClassLocation.hpp +++ b/src/hotspot/share/cds/aotClassLocation.hpp @@ -106,6 +106,7 @@ class AOTClassLocation { // Only boot/app classpaths can contain unnamed module bool has_unnamed_module() const { return from_boot_classpath() || from_app_classpath(); } + char* get_attr(const char* tag) const; char* get_cpattr() const; AOTClassLocation* write_to_archive() const; diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index a84a7b4fb07d..62411a09556b 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -25,6 +25,7 @@ #include "cds/aotClassLocation.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" +#include "cds/cdsProtectionDomain.hpp" #include "cds/dynamicArchive.hpp" #include "cds/heapShared.hpp" #include "classfile/classFileStream.hpp" @@ -368,18 +369,57 @@ ClassPathZipEntry::~ClassPathZipEntry() { FREE_C_HEAP_ARRAY(_zip_name); } -bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name) { - ThreadToNativeFromVM ttn(current); +bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name, Handle class_loader, bool is_multi_release_jar) { // check whether zip archive contains name jint name_len; jint filesize; - jzentry* entry = ZipLibrary::find_entry(_zip, name, &filesize, &name_len); - if (entry == nullptr) { - return false; - } else { - ZipLibrary::free_entry(_zip, entry); - return true; + + { + ThreadToNativeFromVM ttn(current); + jzentry* entry = ZipLibrary::find_entry(_zip, name, &filesize, &name_len); + if (entry != nullptr) { + ZipLibrary::free_entry(_zip, entry); + return true; + } } + +#if INCLUDE_CDS + // Make an upcall to ClassLoader.getResource() if "name" is in a multi-release JAR + // and was not found in the root of the JAR file. This will always be a built-in class + // loader but CDS.getResource() will ensure the resource is retrieved from the correct + // JAR file anyway. + if (class_loader != nullptr && is_multi_release_jar) { + assert(SystemDictionaryShared::is_builtin_loader(ClassLoaderData::class_loader_data(class_loader())), "must be"); + JavaValue result(T_OBJECT); + oop class_name_oop = java_lang_String::create_oop_from_str(name, current); + oop zip_name_oop = CDSProtectionDomain::to_file_URL(_zip_name, Handle(), current); + Handle h_class_name(current, class_name_oop); + Handle h_zip_name(current, zip_name_oop); + + // URL ClassLoader.getResource(String name) + JavaCalls::call_static(&result, + vmClasses::CDS_klass(), + vmSymbols::getResource_name(), + vmSymbols::getResource_cds_signature(), + class_loader, + h_zip_name, + h_class_name, + current); + + // Not using CHECK, the thread must be checked manually + if (current->has_pending_exception()) { + current->clear_pending_exception(); + return false; + } + + assert(result.get_type() == T_OBJECT, "just checking"); + if (result.get_oop() != nullptr) { + return true; + } + } +#endif // INCLUDE_CDS + + return false; } u1* ClassPathZipEntry::open_entry(JavaThread* current, const char* name, jint* filesize, bool nul_terminate) { diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index 2bdfdc0b39de..030e083374c8 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -93,7 +93,7 @@ class ClassPathZipEntry: public ClassPathEntry { const char* name() const { return _zip_name; } ClassPathZipEntry(jzfile* zip, const char* zip_name); virtual ~ClassPathZipEntry(); - bool has_entry(JavaThread* current, const char* name); + bool has_entry(JavaThread* current, const char* name, Handle class_loader, bool is_multi_release_jar); u1* open_entry(JavaThread* current, const char* name, jint* filesize, bool nul_terminate); ClassFileStream* open_stream(JavaThread* current, const char* name); }; diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 76071a550f94..2206da3684a5 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -138,6 +138,7 @@ do_klass(module_Modules_klass, jdk_internal_module_Modules ) \ \ /* support for CDS */ \ + do_klass(CDS_klass, jdk_internal_misc_CDS ) \ do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream ) \ do_klass(URL_klass, java_net_URL ) \ do_klass(Enum_klass, java_lang_Enum ) \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 1de819967e09..f2fc6704d07f 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -750,6 +750,7 @@ class SerializeClosure; template(dumpSharedArchive_signature, "(ZLjava/lang/String;)Ljava/lang/String;") \ template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \ template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \ + template(getResource_name, "getResource") \ template(getResourceAsByteArray_name, "getResourceAsByteArray") \ template(getResourceAsByteArray_signature, "(Ljava/lang/String;)[B") \ template(java_lang_Enum, "java/lang/Enum") \ @@ -759,6 +760,7 @@ class SerializeClosure; template(java_lang_invoke_DelegatingMethodHandle_Holder, "java/lang/invoke/DelegatingMethodHandle$Holder") \ template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \ template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \ + template(getResource_cds_signature, "(Ljava/lang/ClassLoader;Ljava/net/URL;Ljava/lang/String;)Ljava/net/URL;")\ template(jdk_internal_vm_annotation_AOTSafeClassInitializer_signature, "Ljdk/internal/vm/annotation/AOTSafeClassInitializer;")\ template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \ template(java_util_ArrayList, "java/util/ArrayList") \ diff --git a/src/java.base/share/classes/jdk/internal/misc/CDS.java b/src/java.base/share/classes/jdk/internal/misc/CDS.java index b61743c1fb3e..42c8cb5612ba 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CDS.java +++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import java.io.InputStream; import java.io.IOException; import java.io.PrintStream; +import java.net.JarURLConnection; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; @@ -399,6 +401,30 @@ public static boolean needsClassInitBarrier(Class c) { private static native boolean needsClassInitBarrier0(Class c); + /** + * Returns a resource located in a JAR file + * @param loader Class loader used by AOT + * @param jarURL URL of JAR archive which should contain the resource + * @param name Resource name + */ + public static URL getResource(ClassLoader loader, URL jarURL, String name) throws Exception { + URL resource = loader.getResource(name); + + if (resource != null) { + // If the resource is not in the correct JAR file, discard it + if (resource.getProtocol().equalsIgnoreCase("jar")) { + JarURLConnection resourceJarURL = (JarURLConnection)resource.openConnection(); + if (!resourceJarURL.getJarFileURL().equals(jarURL)) { + return null; + } + } else { + return null; + } + } + + return resource; + } + /** * This class is used only by native JVM code at CDS dump time for loading * "unregistered classes", which are archived classes that are intended to diff --git a/test/hotspot/jtreg/runtime/cds/appcds/MultiReleaseJars.java b/test/hotspot/jtreg/runtime/cds/appcds/MultiReleaseJars.java index ac3672ce3fd8..0cf17980717f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/MultiReleaseJars.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/MultiReleaseJars.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ /* * @test MultiReleaseJars * @summary Test multi-release jar with AppCDS. + * @bug 8380847 * @requires vm.cds * @library /test/lib * @run main/othervm/timeout=2400 MultiReleaseJars @@ -34,8 +35,14 @@ import java.io.FileOutputStream; import java.io.PrintStream; import java.io.IOException; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.jar.Attributes.Name; + import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; public class MultiReleaseJars { @@ -60,7 +67,7 @@ static String[] getMain() { static String[] getVersion(int version) { String[] sts = { "package version;", - "public class Version {", + "class Version {", " public int getVersion(){ return " + version + "; }", "}" }; @@ -125,8 +132,9 @@ static void createClassFilesAndJar() throws Exception { JarBuilder.build("version", baseDir, metainf.getAbsolutePath(), "--release", MAJOR_VERSION_STRING, "-C", vDir.getAbsolutePath(), "."); - // the following jar file is for testing case-insensitive "Multi-Release" - // attibute name + // version2.jar is exactly the same as version.jar, except that the manifest file contains + // "multi-Release" instead of "Multi-Release". This is for testing the case-insensitivity of + // the handling of attribute names. String[] meta2 = { "multi-Release: true", "Main-Class: version.Main" @@ -135,6 +143,23 @@ static void createClassFilesAndJar() throws Exception { writeFile(metainf, meta2); JarBuilder.build("version2", baseDir, metainf.getAbsolutePath(), "--release", MAJOR_VERSION_STRING, "-C", vDir.getAbsolutePath(), "."); + + // version3.jar does not include version in the root directory and instead only has it + // in the version specific directory. A private version is used so as to avoid the JAR + // being rejected since there is no matching class in the root directory. + (new File(baseDir, "version/Version.class")).delete(); + writeFile(metainf, meta); + JarBuilder.build("version3", baseDir, metainf.getAbsolutePath(), + "--release", MAJOR_VERSION_STRING, "-C", vDir.getAbsolutePath(), "."); + + // version4.jar is exactly the same as version3.jar, except that the manifest file contains + // "Multi-Release: truex" instead of "true". + Manifest manifest = new Manifest(); + try (JarFile jar = new JarFile("version3.jar")) { + manifest = jar.getManifest(); + } + manifest.getMainAttributes().put(Name.MULTI_RELEASE, "truex"); + JarUtils.updateManifest("version3.jar", "version4.jar", manifest); } static void checkExecOutput(OutputAnalyzer output, String expectedOutput) throws Exception { @@ -158,6 +183,8 @@ public static void main(String... args) throws Exception { String appClasses[] = {"version/Main", "version/Version"}; String appJar = TestCommon.getTestJar("version.jar"); String appJar2 = TestCommon.getTestJar("version2.jar"); + String appJar3 = TestCommon.getTestJar("version3.jar"); + String appJar4 = TestCommon.getTestJar("version4.jar"); String enableMultiRelease = "-Djdk.util.jar.enableMultiRelease=true"; String jarVersion = null; String expectedOutput = null; @@ -235,5 +262,66 @@ public static void main(String... args) throws Exception { output = TestCommon.exec(appJar2, mainClass); checkExecOutput(output, "I am running on version " + MAJOR_VERSION_STRING); + + // 7. AOT Test + SimpleCDSAppTester.of("Multi-Release-AOT") + .addVmArgs("-Xlog:aot", + enableMultiRelease) + .classpath(appJar3) + .appCommandLine(mainClass) + .setTrainingChecker((OutputAnalyzer out) -> { + out.shouldNotMatch("class version/Version cannot be archived because it was not defined"); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("I am running on version " + MAJOR_VERSION_STRING); + }) + .runAOTWorkflow(); + + // 8. AOT Test with space after enableMultiRelease=true + SimpleCDSAppTester.of("Multi-Release-AOT") + .addVmArgs("-Xlog:aot", + enableMultiRelease + " ") + .classpath(appJar3) + .appCommandLine(mainClass) + .setTrainingChecker((OutputAnalyzer out) -> { + out.shouldNotMatch("class version/Version cannot be archived because it was not defined"); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("I am running on version " + MAJOR_VERSION_STRING); + }) + .runAOTWorkflow(); + + // 9. AOT Test with multi-release disabled + SimpleCDSAppTester.of("No-Multi-Release-AOT") + .setCheckExitValue(false) + .addVmArgs("-Xlog:aot", + "-Djdk.util.jar.enableMultiRelease=false") + .classpath(appJar3) + .appCommandLine(mainClass) + .setTrainingChecker((OutputAnalyzer out) -> { + out.shouldNotMatch("class version/Version cannot be archived because it was not defined"); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldContain("java.lang.ClassNotFoundException: version.Version"); + }) + .runAOTWorkflow(); + + // 10. AOT Test with "Multi-Release: truex" instead of "true". The unexpected value + // is ignored and "true" is used by default + SimpleCDSAppTester.of("Multi-Release-AOT-Misspelled") + .setCheckExitValue(false) + .addVmArgs("-Xlog:aot", + enableMultiRelease) + .classpath(appJar4) + .appCommandLine(mainClass) + .setTrainingChecker((OutputAnalyzer out) -> { + out.shouldNotMatch("class version/Version cannot be archived because it was not defined"); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldHaveExitValue(1); + out.shouldContain("java.lang.ClassNotFoundException: version.Version"); + }) + .runAOTWorkflow(); } } From 04a8710ff278ca78e5765a7d604bf0416e603c07 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 2 Sep 2026 21:03:11 +0000 Subject: [PATCH 216/223] 8391694: [BACKOUT] fixes for JDK-8391683, JDK-8391683, and JDK-8380425 Reviewed-by: coleenp, dholmes --- src/hotspot/share/runtime/os.cpp | 15 +---- test/hotspot/gtest/runtime/test_os.cpp | 76 -------------------------- 2 files changed, 1 insertion(+), 90 deletions(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 34707b22c945..9c77c5e30abf 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1339,21 +1339,8 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } // Compressed klass needs to be decoded first. + // Todo: questionable for COH - can we do this better? #ifdef _LP64 - if (UseCompactObjectHeaders) { - markWord mw = (markWord)(uintptr_t)(addr); - static constexpr uintptr_t valhalla_reserved_bits_in_place = right_n_bits(markWord::valhalla_reserved_bits) - << markWord::valhalla_reserved_shift; - static constexpr uintptr_t markbits_must_be_zero = valhalla_reserved_bits_in_place | markWord::self_fwd_bit_in_place; - if ((!mw.has_hash()) && (mw.value() & markbits_must_be_zero) == 0 && Klass::is_valid(mw.klass_without_asserts())) { - st->print(PTR_FORMAT " looks like a valid markword: ", p2i(addr)); - mw.print_on(st); - st->print(" "); - mw.klass()->print_on(st); - return; - } - } - if (((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) { narrowKlass narrow_klass = (narrowKlass)(uintptr_t)addr; Klass* k = CompressedKlassPointers::decode_without_asserts(narrow_klass); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 3cfbb1185601..75d4f7bb9d57 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -29,7 +29,6 @@ #include "runtime/thread.hpp" #include "runtime/threads.hpp" #include "testutils.hpp" -#include "threadHelper.inline.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -124,81 +123,6 @@ TEST_VM(os, page_size_for_region_unaligned) { } } -TEST_VM(os, test_print_markword) { -#ifdef _LP64 - if (UseCompactObjectHeaders) { - JavaThread* THREAD = JavaThread::current(); - ThreadInVMfromNative invm(THREAD); - markWord m0 = vmClasses::Byte_klass()->prototype_header(); - const struct { markWord mw; const char* expected; } patterns[] = { - { markWord(0), "is null"}, - { m0, "mark(is_lock_neutral no_hash age=0) java.lang.Byte" }, - { m0.set_age(2), "age=2" }, - { m0.copy_set_hash(0x12345), "is an unknown value" } - }; - constexpr int nmark = sizeof(patterns) / sizeof(patterns[0]); - for (int i = 0; i < nmark; i++) { - stringStream st; - MutexLocker lock(ClassLoaderDataGraph_lock); - os::print_location(&st, (intptr_t) patterns[i].mw.to_pointer(), true); - ASSERT_THAT(st.base(), testing::HasSubstr(patterns[i].expected)); - } - } -#endif -} - -static void assert_test_pattern(oop& obj, const char* pattern, bool is_present=true) { - stringStream st; - os::print_location(&st, p2i(obj), true); - if (is_present) { - ASSERT_THAT(st.base(), testing::HasSubstr(pattern)); - } else { - ASSERT_THAT(st.base(), testing::Not(testing::HasSubstr(pattern))); - } -} - -TEST_VM(os, test_print_location) { - - JavaThread* THREAD = JavaThread::current(); - ThreadInVMfromNative invm(THREAD); - - oop obj = vmClasses::Byte_klass()->allocate_instance(THREAD); - - { - // wizard mode off, so don't print markword - MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_lock_neutral no_hash", WizardMode); - } - - // WizardMode (not available in release mode) prints details -#ifndef PRODUCT - FlagSetting fs(WizardMode, true); - #endif - HandleMark hm(THREAD); - Handle h_obj(THREAD, obj); - - // Thread tries to lock it. - { - MutexLocker lock(ClassLoaderDataGraph_lock); - ObjectLocker ol(h_obj, THREAD); - assert_test_pattern(obj, "locked"); - assert_test_pattern(obj, "is_lock_neutral", false); - } - - // Unlocked again - { - MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_lock_neutral"); - } - - // Hash the object then print it. - { - intx hash = h_obj->identity_hash(); - MutexLocker lock(ClassLoaderDataGraph_lock); - assert_test_pattern(obj, "is_lock_neutral hash="); - } -} - TEST(os, test_random) { const double m = 2147483647; double mean = 0.0, variance = 0.0, t; From 6fc653f5fcf74fdce2838ddc330cd4dbde9cddfc Mon Sep 17 00:00:00 2001 From: Shawn Emery Date: Wed, 2 Sep 2026 22:16:13 +0000 Subject: [PATCH 217/223] 8388706: PolynomialP256Bench::benchAssign regression after JDK-8355216 Reviewed-by: adinn, qamai --- .../crypto/full/PolynomialP256Bench.java | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java index 34a6bd761ff9..8d2adb7244f4 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,8 @@ import sun.security.util.math.MutableIntegerModuloP; import sun.security.util.math.ImmutableIntegerModuloP; -@Fork(jvmArgs = {"-XX:+AlwaysPreTouch", +@Fork(jvmArgs = {"-XX:+AlwaysPreTouch", "-XX:+UnlockDiagnosticVMOptions", +"-XX:CompileCommand=dontinline,sun.security.util.math.intpoly.IntegerPolynomial$MutableElement::conditionalSet", "--add-exports", "java.base/sun.security.util.math.intpoly=ALL-UNNAMED", "--add-exports", "java.base/sun.security.util.math=ALL-UNNAMED"}, value = 1) @Warmup(iterations = 3, time = 3) @@ -53,9 +54,12 @@ public class PolynomialP256Bench { final IntegerPolynomialP256 residueField = IntegerPolynomialP256.ONE; final BigInteger refx = new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16); - final ImmutableIntegerModuloP x = residueField.getElement(refx); - final ImmutableIntegerModuloP X = montField.getElement(refx); - final ImmutableIntegerModuloP one = montField.get1(); + final ImmutableIntegerModuloP xResidue = residueField.getElement(refx); + final ImmutableIntegerModuloP xMontgomery = montField.getElement(refx); + final ImmutableIntegerModuloP oneResidue = residueField.get1(); + final ImmutableIntegerModuloP oneMontgomery = montField.get1(); + final int ITERATIONS = 10_000; + boolean run = false; @Param({"true", "false"}) private boolean isMontBench; @@ -63,43 +67,54 @@ public class PolynomialP256Bench { @Benchmark public MutableIntegerModuloP benchMultiply() { MutableIntegerModuloP test; + if (isMontBench) { - test = X.mutable(); + test = xMontgomery.mutable(); } else { - test = x.mutable(); + test = xResidue.mutable(); } - - for (int i = 0; i< 10000; i++) { + for (int i = 0; i < ITERATIONS; i++) { test = test.setProduct(test); } + return test; } @Benchmark public MutableIntegerModuloP benchSquare() { MutableIntegerModuloP test; + if (isMontBench) { - test = X.mutable(); + test = xMontgomery.mutable(); } else { - test = x.mutable(); + test = xResidue.mutable(); } - - for (int i = 0; i< 10000; i++) { + for (int i = 0; i < ITERATIONS; i++) { test = test.setSquare(); } + return test; } @Benchmark public MutableIntegerModuloP benchAssign() { - MutableIntegerModuloP test1 = X.mutable(); - MutableIntegerModuloP test2 = one.mutable(); - for (int i = 0; i< 10000; i++) { + MutableIntegerModuloP test1; + MutableIntegerModuloP test2; + + if (isMontBench) { + test1 = xMontgomery.mutable(); + test2 = oneMontgomery.mutable(); + } else { + test1 = xResidue.mutable(); + test2 = oneResidue.mutable(); + } + for (int i = 0; i < ITERATIONS; i++) { test1.conditionalSet(test2, 0); test1.conditionalSet(test2, 1); test2.conditionalSet(test1, 0); test2.conditionalSet(test1, 1); } + return test2; } } From e32a763de9e2cdb5263c545e5b7ba196e002b635 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Wed, 2 Sep 2026 22:40:35 +0000 Subject: [PATCH 218/223] 8386284: Test CompileLevelPrintTest.java fails with RuntimeException: Compiler queue is still not empty Reviewed-by: kvn, thartmann --- .../commands/CompileLevelPrintTest.java | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java b/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java index dcf625c807b3..340c55ef99c3 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java @@ -26,11 +26,13 @@ * @test * @bug 8313713 * @summary Test -XX:CompileCommand=exclude and compileonly with different compilation levels, - * monitoring compilation events in VM -XX:+PrintCompilation and -XX:+PrintTieredEvents output + * monitoring compilation events in VM -XX:+PrintCompilation output * @requires vm.compMode != "Xint" & vm.flavor == "server" * & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null) * & (vm.opt.CompilationMode == "normal" | vm.opt.CompilationMode == null) * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main ${test.main.class} runner */ @@ -39,6 +41,7 @@ import jdk.test.lib.Asserts; import jdk.test.lib.management.InputArguments; import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -58,7 +61,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BooleanSupplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -80,6 +82,7 @@ public class CompileLevelPrintTest { static final String TEST_METHOD_SIGNATURE = TEST_METHOD_NAME_DBL_COLON + "("; static final String TESTEE_WAITING_FOR_START_CMD = "==> waiting for start command"; + static final String TESTEE_WAITING_FOR_STOP_CMD = "==> waiting for stop command"; static final String START_CMD = "start"; static final String STOP_CMD = "stop"; @@ -90,8 +93,8 @@ public class CompileLevelPrintTest { static class TesteeState { final CountDownLatch waitingForStartTest = new CountDownLatch(1); - final AtomicInteger compiler1QueueSize = new AtomicInteger(); - final AtomicInteger compiler2QueueSize = new AtomicInteger(0); + volatile boolean readyForStartTest; + volatile boolean readyForStopTest; final Set compileCommandsReported = Collections.synchronizedSet(new HashSet<>()); volatile Set testMethodCompiledAtLevel = Collections.synchronizedSet(new HashSet<>()); final Set testMethodExcludedAtLevel = Collections.synchronizedSet(new HashSet<>()); @@ -161,9 +164,6 @@ static class Runner { private static final Pattern reCompileCommand = Pattern.compile( "CompileCommand: (.*)"); - private static final Pattern reTieredEvent = Pattern.compile( - "[0-9.]+: \\[(call|loop|compile|force-compile|remove-from-queue|update-in-queue|reprofile|make-not-entrant) " - + "level=\\d \\[([^]]+)] @-?\\d+ queues=(\\d+),(\\d+).*]"); private static final Pattern reCompilation = Pattern.compile( "(\\d+) (C1|C2|no compiler): *(\\d+) ([ %][ s][ !][ b][ n]) ([-0-4 ]) +([^ ]+).*"); private static final Pattern reExcludeCompile = Pattern.compile( @@ -189,9 +189,10 @@ public static void run(String compileCmd, ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", "-XX:+PrintCompilation", "-XX:+CIPrintCompilerName", - "-XX:+PrintTieredEvents", "-XX:+LogVMOutput", "-XX:+LogCompilation", "-XX:" + (tieredCompilation ? "+" : "-") + "TieredCompilation", @@ -215,14 +216,10 @@ public static void run(String compileCmd, matchTesteeMessages(processErrOut, testeeState, "testee-" + process.pid() + ".err")); IO.println("##> Waiting for testee to get ready for the start command"); - if (!testeeState.waitingForStartTest.await(TIMEOUT_SEC, TimeUnit.SECONDS)) { - throw new RuntimeException("No start signal from testee"); - } + testeeState.waitingForStartTest.await(); + Asserts.assertTrue(testeeState.readyForStartTest, + "Testee exited before signaling readiness"); - Asserts.assertTrue(waitUntil(() -> !process.isAlive() - || (testeeState.compiler1QueueSize.get() < 5 - && testeeState.compiler2QueueSize.get() < 5)), - "Compiler queue is still not empty"); Asserts.assertTrue(testeeState.compileCommandsReported.contains( compileCmd + " " + TEST_METHOD_NAME_DOT + " intx " + compileCmd + " = " + cmdCompLevel), "'CompileCommand: " + compileCmd + "...' was not printed"); @@ -234,6 +231,7 @@ public static void run(String compileCmd, processInput.write(START_CMD); processInput.newLine(); processInput.flush(); waitUntil(() -> !process.isAlive() + || testeeState.readyForStopTest || (!expectedCompLevel.isEmpty() && !expectExcludedAtLevels.isEmpty() && expectedCompLevel.equals(testeeState.testMethodCompiledAtLevel) && expectedCompLevel.equals(testeeState.testMethodPrintedAtLevel) @@ -311,17 +309,7 @@ private static void matchVmMessages(BufferedReader testeeOutput, TesteeState tes msg = "Compile command reported: " + matcher.group(1); - } else if ((matcher = reTieredEvent.matcher(line)).matches()) { - testeeState.compiler1QueueSize.set(Integer.parseInt(matcher.group(3))); - testeeState.compiler2QueueSize.set(Integer.parseInt(matcher.group(4))); - } else if ((matcher = reCompilation.matcher(line)).matches()) { - if ("C1".equalsIgnoreCase(matcher.group(2))) { - testeeState.compiler1QueueSize.decrementAndGet(); - } else { - testeeState.compiler2QueueSize.decrementAndGet(); - } - if (matcher.group(6).contains(TEST_METHOD_NAME_DBL_COLON)) { testeeState.testMethodCompiledAtLevel.add(matcher.group(5)); @@ -390,7 +378,11 @@ private static void matchTesteeMessages(BufferedReader testeeErrorOutput, Testee if (TESTEE_WAITING_FOR_START_CMD.equals(line)) { IO.println("##> Testee is waiting for start command"); + testeeState.readyForStartTest = true; testeeState.waitingForStartTest.countDown(); + } else if (TESTEE_WAITING_FOR_STOP_CMD.equals(line)) { + IO.println("##> Testee is waiting for stop command"); + testeeState.readyForStopTest = true; } else if (line.startsWith("==>")) { IO.println(line); } else if (line.startsWith("Exception in thread ") || line.startsWith("at ")) { @@ -401,11 +393,15 @@ private static void matchTesteeMessages(BufferedReader testeeErrorOutput, Testee } } catch (Exception ex) { ex.printStackTrace(); + } finally { + // Unblock the runner if the testee exits before signaling readiness. + testeeState.waitingForStartTest.countDown(); } } } static class Testee { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); private static final CountDownLatch startCmd = new CountDownLatch(1); private static final CountDownLatch stopCmd = new CountDownLatch(1); @@ -419,12 +415,12 @@ static void run() throws IOException, InterruptedException { return; } - // Print 3 times, since the output can be intermixed with + Asserts.assertTrue(waitUntil(() -> WB.getCompileQueuesSize() == 0), + "Compiler queue is still not empty"); + + // Signal readiness after the compiler queues have drained, then wait for the runner. System.err.println(TESTEE_WAITING_FOR_START_CMD); - if (!startCmd.await(TIMEOUT_SEC + 1, TimeUnit.SECONDS)) { - System.err.println("==> 'start' command was not given in stdin"); - return; - } + startCmd.await(); if (stopCmd.getCount() == 0) { return; @@ -432,6 +428,10 @@ static void run() throws IOException, InterruptedException { System.err.println("==> starting test"); runTestCode(); + + // Keep the input pipe open until the runner has consumed the required output. + System.err.println(TESTEE_WAITING_FOR_STOP_CMD); + stopCmd.await(); } finally { System.err.println("==> exiting testee()"); } From 447a07ba2e0c20f18f396174782f76a782f7361b Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 2 Sep 2026 22:42:46 +0000 Subject: [PATCH 219/223] 8379228: C2: Missing trailing_expanded_array_copy flag on MemBar after clone expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Castañeda Lozano Co-authored-by: Kerem Kat Reviewed-by: thartmann, roland --- src/hotspot/share/opto/macroArrayCopy.cpp | 11 +++ src/hotspot/share/opto/memnode.cpp | 30 +++++++++ src/hotspot/share/opto/memnode.hpp | 4 ++ .../arraycopy/TestCloneMemBarKind.java | 67 +++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/arraycopy/TestCloneMemBarKind.java diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 72e82972c2b3..a39f9a00337a 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -1348,6 +1348,17 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { MergeMemNode* merge_mem = nullptr; if (ac->is_clonebasic()) { + // Flag the trailing MemBar so that optimize_simple_memory_chain knows it guards + // an expanded clone. clone_at_expansion virtual function may replace the ArrayCopyNode + // but does not set this flag. + Node* membar = ac->proj_out(TypeFunc::Control)->unique_ctrl_out(); + assert(membar->is_MemBar(), "expect MemBar after clonebasic"); + assert(membar->in(TypeFunc::Memory)->is_MergeMem() && + membar->in(TypeFunc::Memory)->as_MergeMem()->memory_at(Compile::AliasIdxRaw)->is_Proj() && + membar->in(TypeFunc::Memory)->as_MergeMem()->memory_at(Compile::AliasIdxRaw)->in(0) == ac, + "MemBar is from ac"); + membar->as_MemBar()->set_trailing_expanded_array_copy(); + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); bs->clone_at_expansion(this, ac); return; diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index dbd975200844..7353be2f3c07 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -4780,6 +4780,36 @@ void MemBarNode::remove(PhaseIterGVN *igvn) { } } +#ifndef PRODUCT +void MemBarNode::dump_spec(outputStream* st) const { + switch (_kind) { + case Standalone: + st->print(" Standalone"); + break; + case TrailingLoad: + st->print(" TrailingLoad"); + break; + case TrailingStore: + st->print(" TrailingStore"); + break; + case LeadingStore: + st->print(" LeadingStore"); + break; + case TrailingLoadStore: + st->print(" TrailingLoadStore"); + break; + case LeadingLoadStore: + st->print(" LeadingLoadStore"); + break; + case TrailingExpandedArrayCopy: + st->print(" TrailingExpandedArrayCopy"); + break; + default: + fatal("Unimplemented MemBar kind: %d", _kind); + } +} +#endif // !PRODUCT + //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 126acf4d0027..3a44757b8934 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1284,6 +1284,10 @@ class MemBarNode: public MultiNode { static void set_load_store_pair(MemBarNode* leading, MemBarNode* trailing); void remove(PhaseIterGVN *igvn); + +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; +#endif }; // "Acquire" - no following ref can move before (but earlier refs can diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestCloneMemBarKind.java b/test/hotspot/jtreg/compiler/arraycopy/TestCloneMemBarKind.java new file mode 100644 index 000000000000..520a81ff3842 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestCloneMemBarKind.java @@ -0,0 +1,67 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8379228 + * @summary Verify that the trailing MemBar after clone expansion is marked as TrailingExpandedArrayCopy. + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver ${test.main.class} + */ +public class TestCloneMemBarKind { + + public static void main(String[] args) { + TestFramework.run(); + } + + // More than 8 (=ArrayCopyLoadStoreMaxElem) fields so the clone is expanded + // as an arraycopy stub call (is_clonebasic), not as inline loads/stores. + static class BigObj implements Cloneable { + int i1, i2, i3, i4, i5, i6, i7, i8, i9; + + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } + + static BigObj src = new BigObj(); + + @Test + @IR(applyIf = {"ArrayCopyLoadStoreMaxElem", "< 9"}, + phase = CompilePhase.AFTER_MACRO_EXPANSION, + counts = {"MemBar.*TrailingExpandedArrayCopy", ">= 1"}) + static Object testClone() throws CloneNotSupportedException { + return src.clone(); + } + + @Run(test = "testClone") + void runner() throws CloneNotSupportedException { + src.i1 = 42; + testClone(); + } +} From 4104022605933ea1f267aafaae2f148c8c139b77 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 2 Sep 2026 22:43:07 +0000 Subject: [PATCH 220/223] 8384411: Cleanup BarrierSetC2 interface now that Shenandoah, G1 and ZGC use late-barrier expansion Reviewed-by: shade, qamai --- .../share/gc/shared/c2/barrierSetC2.hpp | 24 ---------- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 8 ---- .../shenandoah/c2/shenandoahBarrierSetC2.hpp | 4 -- src/hotspot/share/opto/arraycopynode.cpp | 5 +-- src/hotspot/share/opto/callnode.cpp | 18 +++----- src/hotspot/share/opto/compile.cpp | 11 +---- src/hotspot/share/opto/escape.cpp | 23 ++-------- src/hotspot/share/opto/graphKit.cpp | 3 -- src/hotspot/share/opto/loopnode.cpp | 16 ++----- src/hotspot/share/opto/macro.cpp | 10 +---- src/hotspot/share/opto/matcher.cpp | 8 +--- src/hotspot/share/opto/memnode.cpp | 15 +------ src/hotspot/share/opto/node.cpp | 7 --- src/hotspot/share/opto/phaseX.cpp | 44 ++----------------- src/hotspot/share/opto/phaseX.hpp | 4 -- src/hotspot/share/opto/subnode.cpp | 6 --- 16 files changed, 26 insertions(+), 180 deletions(-) diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index a0876a8842c9..8ff93029e832 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -316,8 +316,6 @@ class BarrierSetC2: public CHeapObj { Node*& fast_oop_ctrl, Node*& fast_oop_rawmem, intx prefetch_lines) const; - virtual Node* ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const { return nullptr; } - // These are general helper methods used by C2 enum ArrayCopyPhase { Parsing, @@ -328,19 +326,9 @@ class BarrierSetC2: public CHeapObj { virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, bool is_clone_instance, ArrayCopyPhase phase) const { return false; } virtual void clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const; - // Support for GC barriers emitted during parsing - virtual bool has_load_barrier_nodes() const { return false; } - virtual bool is_gc_pre_barrier_node(Node* node) const { return false; } - virtual bool is_gc_barrier_node(Node* node) const { return false; } - virtual Node* step_over_gc_barrier(Node* c) const { return c; } - // Support for macro expanded GC barriers - virtual void register_potential_barrier_node(Node* node) const { } - virtual void unregister_potential_barrier_node(Node* node) const { } virtual void eliminate_gc_barrier(PhaseIterGVN* igvn, Node* node) const { } virtual void eliminate_gc_barrier_data(Node* node) const { } - virtual void enqueue_useful_gc_barrier(PhaseIterGVN* igvn, Node* node) const {} - virtual void eliminate_useless_gc_barriers(Unique_Node_List &useful, Compile* C) const {} // Allow barrier sets to have shared state that is preserved across a compilation unit. // This could for example comprise macro nodes to be expanded during macro expansion. @@ -349,9 +337,6 @@ class BarrierSetC2: public CHeapObj { // unit state to be expanded later, then now is the time to do so. virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const { return false; } virtual void final_refinement(Compile* C) const { } - virtual bool optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const { return false; } - virtual bool strip_mined_loops_expanded(LoopOptsMode mode) const { return false; } - virtual bool is_gc_specific_loop_opts_pass(LoopOptsMode mode) const { return false; } // Estimated size of the node barrier in number of C2 Ideal nodes. // This is used to guide heuristics in C2, e.g. whether to unroll a loop. virtual uint estimated_barrier_size(const Node* node) const { return 0; } @@ -368,15 +353,6 @@ class BarrierSetC2: public CHeapObj { virtual void verify_gc_barriers(Compile* compile, CompilePhase phase) const {} #endif - virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode, Unique_Node_List& dead_nodes) const { return false; } - - virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { return false; } - virtual bool escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const { return false; } - virtual bool escape_has_out_with_unsafe_object(Node* n) const { return false; } - - virtual bool matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const { return false; }; - virtual bool matcher_is_store_load_barrier(Node* x, uint xop) const { return false; } - // Whether the given phi node joins OOPs from fast and slow allocation paths. static bool is_allocation(const Node* node); // Elide GC barriers from a Mach node according to elide_dominated_barriers(). diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index b9b2c6a0f7af..298c756ef2b3 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -40,10 +40,6 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" -ShenandoahBarrierSetC2* ShenandoahBarrierSetC2::bsc2() { - return reinterpret_cast(BarrierSet::barrier_set()->barrier_set_c2()); -} - ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena) : BarrierSetC2State(comp_arena), _stubs(new (comp_arena) GrowableArray(comp_arena, 8, 0, nullptr)), @@ -667,10 +663,6 @@ void* ShenandoahBarrierSetC2::create_barrier_state(Arena* comp_arena) const { return new(comp_arena) ShenandoahBarrierSetC2State(comp_arena); } -ShenandoahBarrierSetC2State* ShenandoahBarrierSetC2::state() const { - return reinterpret_cast(Compile::current()->barrier_set_state()); -} - void ShenandoahBarrierSetC2::print_barrier_data(outputStream* os, uint8_t data) { os->print(" Node barriers: "); if ((data & ShenandoahBitStrong) != 0) { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index 097e28a562ef..065c746d93ce 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -110,10 +110,6 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const; public: - static ShenandoahBarrierSetC2* bsc2(); - - ShenandoahBarrierSetC2State* state() const; - // This is the entry-point for the backend to perform accesses through the Access API. virtual void clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const; virtual void clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const; diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 8c94dd41789d..3bf612bb468f 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -818,10 +818,6 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseVal Node* c = mb->in(0); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - // step over g1 gc barrier if we're at e.g. a clone with ReduceInitialCardMarks off - c = bs->step_over_gc_barrier(c); - CallNode* call = nullptr; guarantee(c != nullptr, "step_over_gc_barrier failed, there must be something to step to."); if (c->is_Region()) { @@ -836,6 +832,7 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseVal } } else if (may_modify_helper(t_oop, c->in(0), phase, ac)) { #ifdef ASSERT + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); bool use_ReduceInitialCardMarks = BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) && static_cast(bs)->use_ReduceInitialCardMarks(); assert(c == mb->in(0) || (ac->is_clonebasic() && !use_ReduceInitialCardMarks), "only for clone"); diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index ccfbb9f9a50a..65b5ae1d1de7 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -2362,9 +2362,8 @@ bool AbstractLockNode::find_matching_unlock(const Node* ctrl, LockNode* lock, Node *n = ctrl_proj->in(0); if (n != nullptr && n->is_Unlock()) { UnlockNode *unlock = n->as_Unlock(); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); - Node* unlock_obj = bs->step_over_gc_barrier(unlock->obj_node()); + Node* lock_obj = lock->obj_node(); + Node* unlock_obj = unlock->obj_node(); if (lock_obj->eqv_uncast(unlock_obj) && BoxLockNode::same_slot(lock->box_node(), unlock->box_node()) && !unlock->is_eliminated()) { @@ -2410,9 +2409,8 @@ LockNode *AbstractLockNode::find_matching_lock(UnlockNode* unlock) { } if (ctrl->is_Lock()) { LockNode *lock = ctrl->as_Lock(); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); - Node* unlock_obj = bs->step_over_gc_barrier(unlock->obj_node()); + Node* lock_obj = lock->obj_node(); + Node* unlock_obj = unlock->obj_node(); if (lock_obj->eqv_uncast(unlock_obj) && BoxLockNode::same_slot(lock->box_node(), unlock->box_node())) { lock_result = lock; @@ -2444,9 +2442,8 @@ bool AbstractLockNode::find_lock_and_unlock_through_if(Node* node, LockNode* loc } if (lock1_node != nullptr && lock1_node->is_Lock()) { LockNode *lock1 = lock1_node->as_Lock(); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); - Node* lock1_obj = bs->step_over_gc_barrier(lock1->obj_node()); + Node* lock_obj = lock->obj_node(); + Node* lock1_obj = lock1->obj_node(); if (lock_obj->eqv_uncast(lock1_obj) && BoxLockNode::same_slot(lock->box_node(), lock1->box_node()) && !lock1->is_eliminated()) { @@ -2707,8 +2704,6 @@ bool LockNode::is_nested_lock_region(Compile * c) { return false; } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - obj = bs->step_over_gc_barrier(obj); // Look for external lock for the same object. SafePointNode* sfn = this->as_SafePoint(); JVMState* youngest_jvms = sfn->jvms(); @@ -2719,7 +2714,6 @@ bool LockNode::is_nested_lock_region(Compile * c) { // Loop over monitors for (int idx = 0; idx < num_mon; idx++) { Node* obj_node = sfn->monitor_obj(jvms, idx); - obj_node = bs->step_over_gc_barrier(obj_node); BoxLockNode* box_node = sfn->monitor_box(jvms, idx)->as_BoxLock(); if ((box_node->stack_slot() < stk_slot) && obj_node->eqv_uncast(obj)) { box->set_nested(); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 04247754b1a0..8d8e4111f922 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -436,8 +436,6 @@ void Compile::remove_useless_node(Node* dead) { remove_unstable_if_trap(dead->as_CallStaticJava(), false); } } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bs->unregister_potential_barrier_node(dead); } // Disconnect all useless nodes by disconnecting those at the boundary. @@ -498,8 +496,6 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis } #endif - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bs->eliminate_useless_gc_barriers(useful, this); // clean up the late inline lists remove_useless_late_inlines( &_late_inlines, useful); remove_useless_late_inlines( &_string_late_inlines, useful); @@ -3992,7 +3988,7 @@ void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Uni MemBarNode* mb = n->as_MemBar(); if (mb->trailing_store() || mb->trailing_load_store()) { assert(mb->leading_membar()->trailing_membar() == mb, "bad membar pair"); - Node* mem = BarrierSet::barrier_set()->barrier_set_c2()->step_over_gc_barrier(mb->in(MemBarNode::Precedent)); + Node* mem = mb->in(MemBarNode::Precedent); assert((mb->trailing_store() && mem->is_Store() && mem->as_Store()->is_release()) || (mb->trailing_load_store() && mem->is_LoadStore()), "missing mem op"); } else if (mb->leading()) { @@ -4006,10 +4002,7 @@ void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Uni "unused CallLeafPureNode should have been removed before final graph reshaping"); } #endif - bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->final_graph_reshaping(this, n, nop, dead_nodes); - if (!gc_handled) { - final_graph_reshaping_main_switch(n, frc, nop, dead_nodes); - } + final_graph_reshaping_main_switch(n, frc, nop, dead_nodes); // Collect CFG split points if (n->is_MultiBranch() && !n->is_RangeCheck()) { diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 20c50a074442..5938d6e73b9a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1651,11 +1651,6 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de return; // No need to redefine PointsTo node during first iteration. } int opcode = n->Opcode(); - bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_to_con_graph(this, igvn, delayed_worklist, n, opcode); - if (gc_handled) { - return; // Ignore node if already handled by GC. - } - if (n->is_Call()) { // Arguments to allocation and locking don't escape. if (n->is_AbstractLock()) { @@ -1891,10 +1886,6 @@ void ConnectionGraph::add_final_edges(Node *n) { ((n_ptn != nullptr) && (n_ptn->ideal_node() != nullptr)), "node should be registered already"); int opcode = n->Opcode(); - bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_final_edges(this, _igvn, n, opcode); - if (gc_handled) { - return; // Ignore node if already handled by GC. - } switch (opcode) { case Op_AddP: { Node* base = get_addp_base(n); @@ -2517,7 +2508,6 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { arg_has_oops && (i > TypeFunc::Parms); #ifdef ASSERT if (!(is_arraycopy || - BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(call) || (call->as_CallLeaf()->_name != nullptr && (strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32") == 0 || strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32C") == 0 || @@ -3913,8 +3903,7 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { bool ConnectionGraph::has_oop_node_outs(Node* n) { return n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || - n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || - BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n); + n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN); } // Returns unique pointed java object or null. @@ -4685,9 +4674,7 @@ Node* ConnectionGraph::find_inst_mem(Node* orig_mem, int alias_idx, Unique_Node_ } } else if (proj_in->is_MemBar()) { // Check if there is an array copy for a clone - // Step over GC barrier when ReduceInitialCardMarks is disabled - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* control_proj_ac = bs->step_over_gc_barrier(proj_in->in(0)); + Node* control_proj_ac = proj_in->in(0); if (control_proj_ac->is_Proj() && control_proj_ac->in(0)->is_ArrayCopy()) { // Stop if it is a clone @@ -5214,8 +5201,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, use->is_memory_access_intrinsic() || op == Op_SubTypeCheck || op == Op_InlineType || op == Op_FlatArrayCheck || op == Op_ReinterpretS2HF || - op == Op_ReachabilityFence || - BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) { + op == Op_ReachabilityFence)) { n->dump(); use->dump(); assert(false, "EA: missing allocation reference path"); @@ -5401,8 +5387,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, (op == Op_StrCompressedCopy || op == Op_StrInflatedCopy)) { // They overwrite memory edge corresponding to destination array, memnode_worklist.push(use); - } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) || - use->is_memory_access_intrinsic() || op == Op_FlatArrayCheck)) { + } else if (!use->is_memory_access_intrinsic() && op != Op_FlatArrayCheck) { n->dump(); use->dump(); assert(false, "EA: missing memory path"); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 4d9e3cdbc10d..0e8ef7d98ba7 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4667,9 +4667,6 @@ AllocateNode* AllocateNode::Ideal_allocation(Node* ptr) { return nullptr; } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - ptr = bs->step_over_gc_barrier(ptr); - if (ptr->is_CheckCastPP()) { // strip only one raw-to-oop cast ptr = ptr->in(1); if (ptr == nullptr) return nullptr; diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 2a5f61820202..d60001ad737d 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -222,8 +222,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { if (nb_ctl_proj > 1) { break; } - assert(parent_ctl->is_Start() || parent_ctl->is_MemBar() || parent_ctl->is_Call() || - BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(parent_ctl), "unexpected node"); + assert(parent_ctl->is_Start() || parent_ctl->is_MemBar() || parent_ctl->is_Call(), "unexpected node"); assert(idom(ctl) == parent_ctl, "strange"); next = idom(parent_ctl); } @@ -5302,14 +5301,11 @@ void PhaseIdealLoop::build_and_optimize() { return; } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); // Nothing to do, so get out bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !do_max_unroll && - !do_expand_reachability_fences && !_verify_me && !_verify_only && - !bs->is_gc_specific_loop_opts_pass(_mode) ; + !do_expand_reachability_fences && !_verify_me && !_verify_only; bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn); bool do_optimize_reachability_fences = OptimizeReachabilityFences && (C->reachability_fences_count() > 0); - bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(_mode); if (stop_early && !do_expensive_nodes && !do_optimize_reachability_fences) { return; } @@ -5386,7 +5382,7 @@ void PhaseIdealLoop::build_and_optimize() { // Given early legal placement, try finding counted loops. This placement // is good enough to discover most loop invariants. - if (!_verify_me && !_verify_only && !strip_mined_loops_expanded && !do_expand_reachability_fences) { + if (!_verify_me && !_verify_only && !do_expand_reachability_fences) { _ltree_root->counted_loop( this ); } @@ -5493,10 +5489,6 @@ void PhaseIdealLoop::build_and_optimize() { return; } - if (bs->optimize_loops(this, _mode, visited, nstack, worklist)) { - return; - } - if (ReassociateInvariants && !C->major_progress()) { // Reassociate invariants and prep for split_thru_phi for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { @@ -7191,7 +7183,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { } // Try not to place code on a loop entry projection // which can inhibit range check elimination. - if (least != early && !BarrierSet::barrier_set()->barrier_set_c2()->is_gc_specific_loop_opts_pass(_mode)) { + if (least != early) { Node* ctrl_out = least->unique_ctrl_out_or_null(); if (ctrl_out != nullptr && ctrl_out->is_Loop() && least == ctrl_out->in(LoopNode::EntryControl) && diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index df158c2fcd24..5421e490bc23 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -464,8 +464,6 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type * values.at_put(j, mem); } else if (val->is_Store()) { Node* n = val->in(MemNode::ValueIn); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - n = bs->step_over_gc_barrier(n); if (is_subword_type(ft)) { n = Compile::narrow_value(ft, n, phi_type, &_igvn, true); } @@ -650,8 +648,6 @@ Node* PhaseMacroExpand::value_from_mem(Node* origin, Node* ctl, BasicType ft, co return value_from_alloc(ft, adr_t, alloc); } else if (mem->is_Store()) { Node* n = mem->in(MemNode::ValueIn); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - n = bs->step_over_gc_barrier(n); return n; } else if (mem->is_Phi()) { // attempt to produce a Phi reflecting the values on the input paths of the Phi @@ -805,7 +801,6 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode } while (can_eliminate && worklist.size() > 0) { - BarrierSetC2 *bs = BarrierSet::barrier_set()->barrier_set_c2(); res = worklist.pop(); for (DUIterator_Fast jmax, j = res->fast_outs(jmax); j < jmax && can_eliminate; j++) { Node* use = res->fast_out(j); @@ -827,7 +822,7 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode NOT_PRODUCT(fail_eliminate = "Mismatched access"); can_eliminate = false; } - if (!n->is_Store() && n->Opcode() != Op_CastP2X && !bs->is_gc_pre_barrier_node(n) && !reduce_merge_precheck) { + if (!n->is_Store() && n->Opcode() != Op_CastP2X && !reduce_merge_precheck) { DEBUG_ONLY(disq_node = n;) if (n->is_Load() || n->is_LoadStore()) { NOT_PRODUCT(fail_eliminate = "Field load";) @@ -3284,8 +3279,7 @@ void PhaseMacroExpand::eliminate_macro_nodes(bool eliminate_locks) { n->is_OpaqueConstantBool() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || - n->Opcode() == Op_MinL || - BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(n), + n->Opcode() == Op_MinL, "unknown node type in macro list"); } if (C->failing()) { diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 11d14cb090a4..1542d7c8d625 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -2143,10 +2143,7 @@ void Matcher::find_shared(Node* n) { // Now hack a few special opcodes uint opcode = n->Opcode(); - bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->matcher_find_shared_post_visit(this, n, opcode); - if (!gc_handled) { - find_shared_post_visit(n, opcode); - } + find_shared_post_visit(n, opcode); } else { ShouldNotReachHere(); @@ -2867,8 +2864,7 @@ bool Matcher::post_store_load_barrier(const Node* vmb) { xop == Op_CompareAndSwapL || xop == Op_CompareAndSwapP || xop == Op_CompareAndSwapN || - xop == Op_CompareAndSwapI || - BarrierSet::barrier_set()->barrier_set_c2()->matcher_is_store_load_barrier(x, xop)) { + xop == Op_CompareAndSwapI) { return true; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 7353be2f3c07..274b4d3e1106 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -806,9 +806,7 @@ ArrayCopyNode* MemNode::find_array_copy_clone(Node* ld_alloc, Node* mem) const { mb->in(0)->in(0) != nullptr && mb->in(0)->in(0)->is_ArrayCopy()) { ac = mb->in(0)->in(0)->as_ArrayCopy(); } else { - // Step over GC barrier when ReduceInitialCardMarks is disabled - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* control_proj_ac = bs->step_over_gc_barrier(mb->in(0)); + Node* control_proj_ac = mb->in(0); if (control_proj_ac->is_Proj() && control_proj_ac->in(0)->is_ArrayCopy()) { ac = control_proj_ac->in(0)->as_ArrayCopy(); @@ -1270,9 +1268,6 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { if (ac->as_ArrayCopy()->is_clonebasic()) { assert(ld_alloc != nullptr, "need an alloc"); assert(addp->is_AddP(), "address must be addp"); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - assert(bs->step_over_gc_barrier(addp->in(AddPNode::Base)) == bs->step_over_gc_barrier(ac->in(ArrayCopyNode::Dest)), "strange pattern"); - assert(bs->step_over_gc_barrier(addp->in(AddPNode::Address)) == bs->step_over_gc_barrier(ac->in(ArrayCopyNode::Dest)), "strange pattern"); addp->set_req(AddPNode::Base, src); addp->set_req(AddPNode::Address, src); } else { @@ -1543,8 +1538,6 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { (tp != nullptr) && tp->is_ptr_to_boxed_value()) { intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ignore); - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - base = bs->step_over_gc_barrier(base); if (base != nullptr && base->is_Proj() && base->as_Proj()->_con == TypeFunc::Parms && base->in(0)->is_CallStaticJava() && @@ -2943,12 +2936,6 @@ Node* LoadNode::find_known_klass(PhaseGVN* phase) const { const TypeOopPtr* toop = phase->type(adr)->isa_oopptr(); if (toop == nullptr) { return nullptr; } - // Step over potential GC barrier for OopHandle resolve - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - if (bs->is_gc_barrier_node(base)) { - base = bs->step_over_gc_barrier(base); - } - // We can fetch the klass directly through an AllocateNode. // This works even if the klass is not constant (clone or newArray). if (offset == oopDesc::klass_offset_in_bytes()) { diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index be86ea3df124..7670e6ade89a 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -525,9 +525,6 @@ Node *Node::clone() const { C->add_template_assertion_predicate_opaque(n->as_OpaqueTemplateAssertionPredicate()); } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bs->register_potential_barrier_node(n); - n->set_idx(C->next_unique()); // Get new unique index as well NOT_PRODUCT(n->_igv_idx = C->next_igv_idx()); DEBUG_ONLY( n->verify_construction() ); @@ -659,8 +656,6 @@ void Node::destruct(PhaseValues* phase) { compile->remove_unstable_if_trap(as_CallStaticJava(), false); } } - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bs->unregister_potential_barrier_node(this); // See if the input array was allocated just prior to the object int edge_size = _max*sizeof(void*); @@ -1494,8 +1489,6 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { igvn->add_users_to_worklist( n ); } else if (dead->is_data_proj_of_pure_function(n)) { igvn->_worklist.push(n); - } else { - BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(igvn, n); } } } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index d1b7b6df62fc..d816eeeb816e 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -675,16 +675,6 @@ ConNode* PhaseValues::zerocon(BasicType bt) { } - -//============================================================================= -Node* PhaseGVN::apply_ideal(Node* k, bool can_reshape) { - Node* i = BarrierSet::barrier_set()->barrier_set_c2()->ideal_node(this, k, can_reshape); - if (i == nullptr) { - i = k->Ideal(this, can_reshape); - } - return i; -} - Node* PhaseGVN::apply_identity(Node* n) { DEBUG_ONLY(uint old_unique = is_verify_IGVN_method_return() ? C->unique() : 0;) Node* const i = n->Identity(this); @@ -701,7 +691,7 @@ Node* PhaseGVN::transform(Node* n) { // Apply the Ideal call in a loop until it no longer applies Node* k = n; - Node* i = apply_ideal(k, /*can_reshape=*/false); + Node* i = k->Ideal(this, /*can_reshape=*/false); NOT_PRODUCT(uint loop_count = 1;) while (i != nullptr) { assert(i->_idx >= k->_idx, "Idealize should return new nodes, use Identity to return old nodes" ); @@ -711,7 +701,7 @@ Node* PhaseGVN::transform(Node* n) { dump_infinite_loop_info(i, "PhaseGVN::transform"); } #endif - i = apply_ideal(k, /*can_reshape=*/false); + i = k->Ideal(this, /*can_reshape=*/false); NOT_PRODUCT(loop_count++;) } NOT_PRODUCT(if (loop_count != 0) { set_progress(); }) @@ -2222,7 +2212,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { DEBUG_ONLY(bool is_new = (k->outcnt() == 0);) C->remove_modified_node(k); DEBUG_ONLY(uint hash_before = is_verify_IGVN_method_return() ? k->hash() : 0;) - Node* i = apply_ideal(k, /*can_reshape=*/true); + Node* i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes"); assert(!is_verify_IGVN_method_return() || k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); @@ -2251,7 +2241,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { DEBUG_ONLY(is_new = (k->outcnt() == 0);) C->remove_modified_node(k); DEBUG_ONLY(uint hash_before = is_verify_IGVN_method_return() ? k->hash() : 0;) - i = apply_ideal(k, /*can_reshape=*/true); + i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes"); assert(!is_verify_IGVN_method_return() || k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name()); @@ -2374,8 +2364,6 @@ void PhaseIterGVN::remove_globally_dead_node(Node* dead, NodeOrigin origin) { } } else if (dead->is_data_proj_of_pure_function(in)) { _worklist.push(in); - } else { - BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(this, in); } if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory && in->is_Proj() && in->in(0) != nullptr && in->in(0)->is_Initialize()) { @@ -2806,9 +2794,6 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ // Loading the java mirror from a Klass requires two loads and the type // of the mirror load depends on the type of 'n'. See LoadNode::Value(). // LoadBarrier?(LoadP(LoadP(AddP(foo:Klass, #java_mirror)))) - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bool has_load_barrier_nodes = bs->has_load_barrier_nodes(); - // Needed because of PhaseMacroExpand::expand_mh_intrinsic_return if (use_op == Op_CastP2X) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { @@ -2832,12 +2817,6 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ Node* u = use->fast_out(i2); const Type* ut = u->bottom_type(); if (u->Opcode() == Op_LoadP && ut->isa_instptr()) { - if (has_load_barrier_nodes) { - // Search for load barriers behind the load - add_users_to_worklist_if(worklist, u, [&](Node* b) { - return bs->is_gc_barrier_node(b); - }); - } worklist.push(u); } } @@ -3245,30 +3224,17 @@ void PhaseCCP::push_cast(Unique_Node_List& worklist, const Node* use) { // Loading the java mirror from a Klass requires two loads and the type of the mirror load depends on the type of 'n'. // See LoadNode::Value(). void PhaseCCP::push_loadp(Unique_Node_List& worklist, const Node* use) const { - BarrierSetC2* barrier_set = BarrierSet::barrier_set()->barrier_set_c2(); - bool has_load_barrier_nodes = barrier_set->has_load_barrier_nodes(); - if (use->Opcode() == Op_LoadP && use->bottom_type()->isa_rawptr()) { for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { Node* loadp = use->fast_out(i); const Type* ut = loadp->bottom_type(); if (loadp->Opcode() == Op_LoadP && ut->isa_instptr() && ut != type(loadp)) { - if (has_load_barrier_nodes) { - // Search for load barriers behind the load - push_load_barrier(worklist, barrier_set, loadp); - } worklist.push(loadp); } } } } -void PhaseCCP::push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2* barrier_set, const Node* use) { - add_users_to_worklist_if(worklist, use, [&](Node* u) { - return barrier_set->is_gc_barrier_node(u); - }); -} - // AndI/L::Value() optimizes patterns similar to (v << 2) & 3, or CON & 3 to zero if they are bitwise disjoint. // Add the AndI/L nodes back to the worklist to re-apply Value() in case the value is now a constant or shift // value changed. @@ -3626,8 +3592,6 @@ void Node::set_req_X( uint i, Node *n, PhaseIterGVN *igvn ) { default: break; } - - BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(igvn, old); } } diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 4e706f8c4783..c57529213933 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -448,9 +448,6 @@ class PhaseGVN : public PhaseValues { bool is_dominator(Node *d, Node *n) { return is_dominator_helper(d, n, true); } - // Helper to call Node::Ideal() and BarrierSetC2::ideal_node(). - Node* apply_ideal(Node* i, bool can_reshape); - // Helper to call Node::Identity() and verify that it returns an existing node. Node* apply_identity(Node* n); @@ -720,7 +717,6 @@ class PhaseCCP : public PhaseIterGVN { static void push_counted_loop_phi(Unique_Node_List& worklist, Node* parent, const Node* use); static void push_cast(Unique_Node_List& worklist, const Node* use); void push_loadp(Unique_Node_List& worklist, const Node* use) const; - static void push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2* barrier_set, const Node* use); void push_and(Unique_Node_List& worklist, const Node* parent, const Node* use) const; void push_cast_ii(Unique_Node_List& worklist, const Node* parent, const Node* use) const; void push_opaque_zero_trip_guard(Unique_Node_List& worklist, const Node* use) const; diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index d45bfa235686..4ea516547029 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1070,12 +1070,6 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { } static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n, bool& might_be_an_array) { - // Return the klass node for (indirect load from OopHandle) - // LoadBarrier?(LoadP(LoadP(AddP(foo:Klass, #java_mirror)))) - // or null if not matching. - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - n = bs->step_over_gc_barrier(n); - if (n->Opcode() != Op_LoadP) return nullptr; const TypeInstPtr* tp = phase->type(n)->isa_instptr(); From b4930a24bfeee8002143e5d9885567cb03e57000 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 2 Sep 2026 23:29:37 +0000 Subject: [PATCH 221/223] 8391593: Typos and omissions in VarHandle test templates Reviewed-by: jvernee --- .../VarHandleTestAccessBoolean.java | 8 +- .../VarHandles/VarHandleTestAccessByte.java | 14 +-- .../VarHandles/VarHandleTestAccessChar.java | 14 +-- .../VarHandles/VarHandleTestAccessDouble.java | 14 +-- .../VarHandles/VarHandleTestAccessFloat.java | 14 +-- .../VarHandles/VarHandleTestAccessInt.java | 14 +-- .../VarHandles/VarHandleTestAccessLong.java | 14 +-- ...arHandleTestAccessNullRestrictedValue.java | 96 ++++++++--------- .../VarHandles/VarHandleTestAccessShort.java | 14 +-- .../VarHandles/VarHandleTestAccessString.java | 30 +++--- .../VarHandles/VarHandleTestAccessValue.java | 30 +++--- .../VarHandleTestByteArrayAsChar.java | 16 +-- .../VarHandleTestByteArrayAsDouble.java | 16 +-- .../VarHandleTestByteArrayAsFloat.java | 16 +-- .../VarHandleTestByteArrayAsInt.java | 16 +-- .../VarHandleTestByteArrayAsLong.java | 16 +-- .../VarHandleTestByteArrayAsShort.java | 16 +-- ...arHandleTestMethodHandleAccessBoolean.java | 34 ++++-- .../VarHandleTestMethodHandleAccessByte.java | 34 ++++-- .../VarHandleTestMethodHandleAccessChar.java | 34 ++++-- ...VarHandleTestMethodHandleAccessDouble.java | 34 ++++-- .../VarHandleTestMethodHandleAccessFloat.java | 34 ++++-- .../VarHandleTestMethodHandleAccessInt.java | 34 ++++-- .../VarHandleTestMethodHandleAccessLong.java | 34 ++++-- ...MethodHandleAccessNullRestrictedValue.java | 34 ++++-- .../VarHandleTestMethodHandleAccessShort.java | 34 ++++-- ...VarHandleTestMethodHandleAccessString.java | 34 ++++-- .../VarHandleTestMethodHandleAccessValue.java | 34 ++++-- .../VarHandleTestMethodTypeBoolean.java | 90 ++++++++-------- .../VarHandleTestMethodTypeByte.java | 98 ++++++++--------- .../VarHandleTestMethodTypeChar.java | 98 ++++++++--------- .../VarHandleTestMethodTypeDouble.java | 30 +++--- .../VarHandleTestMethodTypeFloat.java | 30 +++--- .../VarHandleTestMethodTypeInt.java | 98 ++++++++--------- .../VarHandleTestMethodTypeLong.java | 98 ++++++++--------- ...ndleTestMethodTypeNullRestrictedValue.java | 22 ++-- .../VarHandleTestMethodTypeShort.java | 98 ++++++++--------- .../VarHandleTestMethodTypeString.java | 22 ++-- .../VarHandleTestMethodTypeValue.java | 22 ++-- .../X-VarHandleTestAccess.java.template | 102 +++++++++--------- ...X-VarHandleTestByteArrayView.java.template | 16 +-- ...HandleTestMethodHandleAccess.java.template | 34 ++++-- .../X-VarHandleTestMethodType.java.template | 98 ++++++++--------- 43 files changed, 952 insertions(+), 736 deletions(-) diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index c48b1678fc10..50801fcadef7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessBoolean * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessBoolean * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessBoolean @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessBoolean recv, VarHandle vh // Lazy { boolean x = (boolean) vh.getAcquire(recv); - assertEquals(true, x, "getRelease boolean value"); + assertEquals(true, x, "getAcquire boolean value"); } // Opaque @@ -377,7 +377,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { boolean x = (boolean) vh.getAcquire(); - assertEquals(true, x, "getRelease boolean value"); + assertEquals(true, x, "getAcquire boolean value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index 234db06638ed..abfe770f29af 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessByte * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessByte * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessByte @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessByte recv, VarHandle vh) { // Lazy { byte x = (byte) vh.getAcquire(recv); - assertEquals((byte)0x01, x, "getRelease byte value"); + assertEquals((byte)0x01, x, "getAcquire byte value"); } // Opaque @@ -366,7 +366,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { byte x = (byte) vh.getAcquire(); - assertEquals((byte)0x01, x, "getRelease byte value"); + assertEquals((byte)0x01, x, "getAcquire byte value"); } // Opaque @@ -610,7 +610,7 @@ static void testInstanceField(VarHandleTestAccessByte recv, VarHandle vh) { vh.set(recv, (byte)0x01); byte o = (byte) vh.getAndAddRelease(recv, (byte)0x23); - assertEquals((byte)0x01, o, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) vh.get(recv); assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } @@ -918,7 +918,7 @@ static void testStaticField(VarHandle vh) { vh.set((byte)0x01); byte o = (byte) vh.getAndAddRelease((byte)0x23); - assertEquals((byte)0x01, o, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) vh.get(); assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } @@ -1229,7 +1229,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, (byte)0x01); byte o = (byte) vh.getAndAddRelease(array, i, (byte)0x23); - assertEquals((byte)0x01, o, "getAndAddReleasebyte"); + assertEquals((byte)0x01, o, "getAndAddRelease byte"); byte x = (byte) vh.get(array, i); assertEquals((byte)((byte)0x01 + (byte)0x23), x, "getAndAddRelease byte value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index 7d3a57f09872..e4836c9a6f0b 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessChar * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessChar * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessChar @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessChar recv, VarHandle vh) { // Lazy { char x = (char) vh.getAcquire(recv); - assertEquals('\u0123', x, "getRelease char value"); + assertEquals('\u0123', x, "getAcquire char value"); } // Opaque @@ -366,7 +366,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { char x = (char) vh.getAcquire(); - assertEquals('\u0123', x, "getRelease char value"); + assertEquals('\u0123', x, "getAcquire char value"); } // Opaque @@ -610,7 +610,7 @@ static void testInstanceField(VarHandleTestAccessChar recv, VarHandle vh) { vh.set(recv, '\u0123'); char o = (char) vh.getAndAddRelease(recv, '\u4567'); - assertEquals('\u0123', o, "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) vh.get(recv); assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } @@ -918,7 +918,7 @@ static void testStaticField(VarHandle vh) { vh.set('\u0123'); char o = (char) vh.getAndAddRelease('\u4567'); - assertEquals('\u0123', o, "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) vh.get(); assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } @@ -1229,7 +1229,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, '\u0123'); char o = (char) vh.getAndAddRelease(array, i, '\u4567'); - assertEquals('\u0123', o, "getAndAddReleasechar"); + assertEquals('\u0123', o, "getAndAddRelease char"); char x = (char) vh.get(array, i); assertEquals((char)('\u0123' + '\u4567'), x, "getAndAddRelease char value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index 987cad711da2..d5b2a02418b6 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessDouble * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessDouble * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessDouble @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessDouble recv, VarHandle vh) // Lazy { double x = (double) vh.getAcquire(recv); - assertEquals(1.0d, x, "getRelease double value"); + assertEquals(1.0d, x, "getAcquire double value"); } // Opaque @@ -401,7 +401,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { double x = (double) vh.getAcquire(); - assertEquals(1.0d, x, "getRelease double value"); + assertEquals(1.0d, x, "getAcquire double value"); } // Opaque @@ -680,7 +680,7 @@ static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) { vh.set(recv, 1.0d); double o = (double) vh.getAndAddRelease(recv, 2.0d); - assertEquals(1.0d, o, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) vh.get(recv); assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } @@ -940,7 +940,7 @@ static void testStaticField(VarHandle vh) { vh.set(1.0d); double o = (double) vh.getAndAddRelease(2.0d); - assertEquals(1.0d, o, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) vh.get(); assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } @@ -1203,7 +1203,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, 1.0d); double o = (double) vh.getAndAddRelease(array, i, 2.0d); - assertEquals(1.0d, o, "getAndAddReleasedouble"); + assertEquals(1.0d, o, "getAndAddRelease double"); double x = (double) vh.get(array, i); assertEquals((double)(1.0d + 2.0d), x, "getAndAddRelease double value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index 55f07405138c..40eee3fadcfe 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessFloat * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessFloat * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessFloat @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessFloat recv, VarHandle vh) // Lazy { float x = (float) vh.getAcquire(recv); - assertEquals(1.0f, x, "getRelease float value"); + assertEquals(1.0f, x, "getAcquire float value"); } // Opaque @@ -401,7 +401,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { float x = (float) vh.getAcquire(); - assertEquals(1.0f, x, "getRelease float value"); + assertEquals(1.0f, x, "getAcquire float value"); } // Opaque @@ -680,7 +680,7 @@ static void testInstanceField(VarHandleTestAccessFloat recv, VarHandle vh) { vh.set(recv, 1.0f); float o = (float) vh.getAndAddRelease(recv, 2.0f); - assertEquals(1.0f, o, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) vh.get(recv); assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } @@ -940,7 +940,7 @@ static void testStaticField(VarHandle vh) { vh.set(1.0f); float o = (float) vh.getAndAddRelease(2.0f); - assertEquals(1.0f, o, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) vh.get(); assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } @@ -1203,7 +1203,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, 1.0f); float o = (float) vh.getAndAddRelease(array, i, 2.0f); - assertEquals(1.0f, o, "getAndAddReleasefloat"); + assertEquals(1.0f, o, "getAndAddRelease float"); float x = (float) vh.get(array, i); assertEquals((float)(1.0f + 2.0f), x, "getAndAddRelease float value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index 80509800a507..de390262f7cc 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessInt * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessInt * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessInt @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessInt recv, VarHandle vh) { // Lazy { int x = (int) vh.getAcquire(recv); - assertEquals(0x01234567, x, "getRelease int value"); + assertEquals(0x01234567, x, "getAcquire int value"); } // Opaque @@ -366,7 +366,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { int x = (int) vh.getAcquire(); - assertEquals(0x01234567, x, "getRelease int value"); + assertEquals(0x01234567, x, "getAcquire int value"); } // Opaque @@ -610,7 +610,7 @@ static void testInstanceField(VarHandleTestAccessInt recv, VarHandle vh) { vh.set(recv, 0x01234567); int o = (int) vh.getAndAddRelease(recv, 0x89ABCDEF); - assertEquals(0x01234567, o, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) vh.get(recv); assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } @@ -918,7 +918,7 @@ static void testStaticField(VarHandle vh) { vh.set(0x01234567); int o = (int) vh.getAndAddRelease(0x89ABCDEF); - assertEquals(0x01234567, o, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) vh.get(); assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } @@ -1229,7 +1229,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, 0x01234567); int o = (int) vh.getAndAddRelease(array, i, 0x89ABCDEF); - assertEquals(0x01234567, o, "getAndAddReleaseint"); + assertEquals(0x01234567, o, "getAndAddRelease int"); int x = (int) vh.get(array, i); assertEquals((int)(0x01234567 + 0x89ABCDEF), x, "getAndAddRelease int value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index ac8db96df9e2..b5fa2ec390d1 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessLong * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessLong * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessLong @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessLong recv, VarHandle vh) { // Lazy { long x = (long) vh.getAcquire(recv); - assertEquals(0x0123456789ABCDEFL, x, "getRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "getAcquire long value"); } // Opaque @@ -366,7 +366,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { long x = (long) vh.getAcquire(); - assertEquals(0x0123456789ABCDEFL, x, "getRelease long value"); + assertEquals(0x0123456789ABCDEFL, x, "getAcquire long value"); } // Opaque @@ -610,7 +610,7 @@ static void testInstanceField(VarHandleTestAccessLong recv, VarHandle vh) { vh.set(recv, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(recv, 0xCAFEBABECAFEBABEL); - assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) vh.get(recv); assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } @@ -918,7 +918,7 @@ static void testStaticField(VarHandle vh) { vh.set(0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(0xCAFEBABECAFEBABEL); - assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) vh.get(); assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } @@ -1229,7 +1229,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, 0x0123456789ABCDEFL); long o = (long) vh.getAndAddRelease(array, i, 0xCAFEBABECAFEBABEL); - assertEquals(0x0123456789ABCDEFL, o, "getAndAddReleaselong"); + assertEquals(0x0123456789ABCDEFL, o, "getAndAddRelease long"); long x = (long) vh.get(array, i); assertEquals((long)(0x0123456789ABCDEFL + 0xCAFEBABECAFEBABEL), x, "getAndAddRelease long value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java index db3743b31e41..346c7beb1934 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessNullRestrictedValue.java @@ -30,8 +30,8 @@ * java.base/jdk.internal.value * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessNullRestrictedValue * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessNullRestrictedValue * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessNullRestrictedValue @@ -340,7 +340,7 @@ static void testInstanceFinalField(VarHandleTestAccessNullRestrictedValue recv, // Lazy { NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(recv); - assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getRelease NullRestrictedValue value"); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getAcquire NullRestrictedValue value"); } // Opaque @@ -435,7 +435,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { NullRestrictedValue x = (NullRestrictedValue) vh.getAcquire(); - assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getRelease NullRestrictedValue value"); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "getAcquire NullRestrictedValue value"); } // Opaque @@ -1363,57 +1363,57 @@ static void testArrayStoreException(VarHandle vh) throws Throwable { }); // CompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetVolatile - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchange - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // GetAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, value); }); } @@ -1442,57 +1442,57 @@ static void testInstanceFieldNullPointerException(VarHandleTestAccessNullRestric }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(recv, value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(recv, value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(recv, value); }); } @@ -1521,57 +1521,57 @@ static void testStaticFieldNullPointerException(VarHandle vh) throws Throwable { }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet(NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain(NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet(NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire(NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease(NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(NullRestrictedValue.of((byte)20,(short)1854), value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(value); }); } @@ -1601,57 +1601,57 @@ static void testArrayNullPointerException(VarHandle vh) throws Throwable { }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(array, 0, NullRestrictedValue.of((byte)20,(short)1854), value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, value); }); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index 1da5fe5018b2..31beeb6e31f2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessShort * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessShort * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessShort @@ -317,7 +317,7 @@ static void testInstanceFinalField(VarHandleTestAccessShort recv, VarHandle vh) // Lazy { short x = (short) vh.getAcquire(recv); - assertEquals((short)0x0123, x, "getRelease short value"); + assertEquals((short)0x0123, x, "getAcquire short value"); } // Opaque @@ -366,7 +366,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { short x = (short) vh.getAcquire(); - assertEquals((short)0x0123, x, "getRelease short value"); + assertEquals((short)0x0123, x, "getAcquire short value"); } // Opaque @@ -610,7 +610,7 @@ static void testInstanceField(VarHandleTestAccessShort recv, VarHandle vh) { vh.set(recv, (short)0x0123); short o = (short) vh.getAndAddRelease(recv, (short)0x4567); - assertEquals((short)0x0123, o, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) vh.get(recv); assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } @@ -918,7 +918,7 @@ static void testStaticField(VarHandle vh) { vh.set((short)0x0123); short o = (short) vh.getAndAddRelease((short)0x4567); - assertEquals((short)0x0123, o, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) vh.get(); assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } @@ -1229,7 +1229,7 @@ static void testArray(VarHandle vh) { vh.set(array, i, (short)0x0123); short o = (short) vh.getAndAddRelease(array, i, (short)0x4567); - assertEquals((short)0x0123, o, "getAndAddReleaseshort"); + assertEquals((short)0x0123, o, "getAndAddRelease short"); short x = (short) vh.get(array, i); assertEquals((short)((short)0x0123 + (short)0x4567), x, "getAndAddRelease short value"); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 614528d294b4..b720ce80d649 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -27,8 +27,8 @@ * @test * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessString * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessString * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessString @@ -325,7 +325,7 @@ static void testInstanceFinalField(VarHandleTestAccessString recv, VarHandle vh) // Lazy { String x = (String) vh.getAcquire(recv); - assertEquals("foo", x, "getRelease String value"); + assertEquals("foo", x, "getAcquire String value"); } // Opaque @@ -420,7 +420,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { String x = (String) vh.getAcquire(); - assertEquals("foo", x, "getRelease String value"); + assertEquals("foo", x, "getAcquire String value"); } // Opaque @@ -1348,57 +1348,57 @@ static void testArrayStoreException(VarHandle vh) throws Throwable { }); // CompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.compareAndSet(array, 0, "foo", value); }); // WeakCompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, "foo", value); }); // WeakCompareAndSetVolatile - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSet(array, 0, "foo", value); }); // WeakCompareAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, "foo", value); }); // WeakCompareAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, "foo", value); }); // CompareAndExchange - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.compareAndExchange(array, 0, "foo", value); }); // CompareAndExchangeAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.compareAndExchangeAcquire(array, 0, "foo", value); }); // CompareAndExchangeRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.compareAndExchangeRelease(array, 0, "foo", value); }); // GetAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { String x = (String) vh.getAndSetRelease(array, 0, value); }); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java index 7b974a3bed90..db743f7a3349 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessValue.java @@ -30,8 +30,8 @@ * java.base/jdk.internal.value * @run junit/othervm -Diters=10 -Xint VarHandleTestAccessValue * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccessValue * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccessValue @@ -328,7 +328,7 @@ static void testInstanceFinalField(VarHandleTestAccessValue recv, VarHandle vh) // Lazy { Value x = (Value) vh.getAcquire(recv); - assertEquals(Value.getInstance(10), x, "getRelease Value value"); + assertEquals(Value.getInstance(10), x, "getAcquire Value value"); } // Opaque @@ -423,7 +423,7 @@ static void testStaticFinalField(VarHandle vh) { // Lazy { Value x = (Value) vh.getAcquire(); - assertEquals(Value.getInstance(10), x, "getRelease Value value"); + assertEquals(Value.getInstance(10), x, "getAcquire Value value"); } // Opaque @@ -1351,57 +1351,57 @@ static void testArrayStoreException(VarHandle vh) throws Throwable { }); // CompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.compareAndSet(array, 0, Value.getInstance(10), value); }); // WeakCompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, Value.getInstance(10), value); }); // WeakCompareAndSetVolatile - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSet(array, 0, Value.getInstance(10), value); }); // WeakCompareAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, Value.getInstance(10), value); }); // WeakCompareAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, Value.getInstance(10), value); }); // CompareAndExchange - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.compareAndExchange(array, 0, Value.getInstance(10), value); }); // CompareAndExchangeAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.compareAndExchangeAcquire(array, 0, Value.getInstance(10), value); }); // CompareAndExchangeRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.compareAndExchangeRelease(array, 0, Value.getInstance(10), value); }); // GetAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { Value x = (Value) vh.getAndSetRelease(array, 0, value); }); } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java index 26ac4aab893c..6dfe05e6e0af 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsChar * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsChar * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsChar @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsChar extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -820,7 +820,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { char x = (char) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease char value"); + assertEquals(v, x, "getAcquire char value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java index a9e1e603c5d3..3be3bb800e05 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsDouble * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsDouble * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsDouble @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsDouble extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -1122,7 +1122,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { double x = (double) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease double value"); + assertEquals(v, x, "getAcquire double value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java index 486487518e93..759bd264f876 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsFloat * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsFloat * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsFloat @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsFloat extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -1122,7 +1122,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { float x = (float) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease float value"); + assertEquals(v, x, "getAcquire float value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java index ce55c3d5e31c..da8094154cd4 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsInt * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsInt * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsInt @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -1388,7 +1388,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { int x = (int) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease int value"); + assertEquals(v, x, "getAcquire int value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java index 763703b60798..793f945722ae 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsLong * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsLong * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsLong @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsLong extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -1388,7 +1388,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { long x = (long) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease long value"); + assertEquals(v, x, "getAcquire long value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java index 7a3bc069c224..305139856dfd 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAsShort * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAsShort * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAsShort @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAsShort extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -73,12 +73,12 @@ public List setupVarHandleSources(boolean same) { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -820,7 +820,7 @@ static void testArrayReadOnly(ByteBufferSource bs, VarHandleSource vhs) { // Lazy { short x = (short) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease short value"); + assertEquals(v, x, "getAcquire short value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java index 88535d597f5a..eb579029e367 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessBoolean */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handl // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, true); + boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, false); assertEquals(true, o, "getAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(false, x, "getAndSet boolean value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, true); + + boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, false); + assertEquals(true, o, "getAndSetAcquire boolean"); + boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(false, x, "getAndSetAcquire boolean value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, true); + + boolean o = (boolean) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, false); + assertEquals(true, o, "getAndSetRelease boolean"); + boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(false, x, "getAndSetRelease boolean value"); + } + // get and bitwise or { @@ -560,7 +580,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(false, false); assertEquals(success, false, "failing weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(true, x, "failing weakCompareAndSetRe boolean value"); + assertEquals(true, x, "failing weakCompareAndSet boolean value"); } // Compare set and get @@ -573,7 +593,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(false, x, "getAndSet boolean value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(true); @@ -583,7 +602,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(false, x, "getAndSetAcquire boolean value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(true); @@ -833,10 +851,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, true, false); - assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, true, false); + assertEquals(success, false, "failing weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(false, x, "failing weakCompareAndSetAcquire boolean value"); + assertEquals(false, x, "failing weakCompareAndSetRelease boolean value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java index d97875247404..514d19eff951 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessByte */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); + byte o = (byte) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, (byte)0x23); assertEquals((byte)0x01, o, "getAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals((byte)0x23, x, "getAndSet byte value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); + + byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, (byte)0x23); + assertEquals((byte)0x01, o, "getAndSetAcquire byte"); + byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); + + byte o = (byte) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, (byte)0x23); + assertEquals((byte)0x01, o, "getAndSetRelease byte"); + byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals((byte)0x23, x, "getAndSetRelease byte value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, (byte)0x01); @@ -582,7 +602,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals((byte)0x01, x, "failing weakCompareAndSetRe byte value"); + assertEquals((byte)0x01, x, "failing weakCompareAndSet byte value"); } // Compare set and get @@ -595,7 +615,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals((byte)0x23, x, "getAndSet byte value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); @@ -605,7 +624,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals((byte)0x23, x, "getAndSetAcquire byte value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact((byte)0x01); @@ -877,10 +895,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (byte)0x01, (byte)0x45); - assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, (byte)0x01, (byte)0x45); + assertEquals(success, false, "failing weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals((byte)0x23, x, "failing weakCompareAndSetAcquire byte value"); + assertEquals((byte)0x23, x, "failing weakCompareAndSetRelease byte value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java index f9d714f3cd0a..4642e8196a03 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessChar */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); + char o = (char) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, '\u4567'); assertEquals('\u0123', o, "getAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals('\u4567', x, "getAndSet char value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); + + char o = (char) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, '\u4567'); + assertEquals('\u0123', o, "getAndSetAcquire char"); + char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals('\u4567', x, "getAndSetAcquire char value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); + + char o = (char) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, '\u4567'); + assertEquals('\u0123', o, "getAndSetRelease char"); + char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals('\u4567', x, "getAndSetRelease char value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, '\u0123'); @@ -582,7 +602,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals('\u0123', x, "failing weakCompareAndSetRe char value"); + assertEquals('\u0123', x, "failing weakCompareAndSet char value"); } // Compare set and get @@ -595,7 +615,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals('\u4567', x, "getAndSet char value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact('\u0123'); @@ -605,7 +624,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals('\u4567', x, "getAndSetAcquire char value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact('\u0123'); @@ -877,10 +895,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, '\u0123', '\u89AB'); - assertEquals(success, false, "failing weakCompareAndSetAcquire char"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, '\u0123', '\u89AB'); + assertEquals(success, false, "failing weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals('\u4567', x, "failing weakCompareAndSetAcquire char value"); + assertEquals('\u4567', x, "failing weakCompareAndSetRelease char value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java index 120897a9352c..b1f88a18ca8f 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessDouble */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handle // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); + double o = (double) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2.0d); assertEquals(1.0d, o, "getAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(2.0d, x, "getAndSet double value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); + + double o = (double) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, 2.0d); + assertEquals(1.0d, o, "getAndSetAcquire double"); + double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(2.0d, x, "getAndSetAcquire double value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); + + double o = (double) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, 2.0d); + assertEquals(1.0d, o, "getAndSetRelease double"); + double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(2.0d, x, "getAndSetRelease double value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0d); @@ -504,7 +524,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(1.0d, x, "failing weakCompareAndSetRe double value"); + assertEquals(1.0d, x, "failing weakCompareAndSet double value"); } // Compare set and get @@ -517,7 +537,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(2.0d, x, "getAndSet double value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(1.0d); @@ -527,7 +546,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(2.0d, x, "getAndSetAcquire double value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(1.0d); @@ -721,10 +739,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 1.0d, 3.0d); - assertEquals(success, false, "failing weakCompareAndSetAcquire double"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 1.0d, 3.0d); + assertEquals(success, false, "failing weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(2.0d, x, "failing weakCompareAndSetAcquire double value"); + assertEquals(2.0d, x, "failing weakCompareAndSetRelease double value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java index acdf5d81cec9..1836b1729dc3 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessFloat */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); + float o = (float) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2.0f); assertEquals(1.0f, o, "getAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(2.0f, x, "getAndSet float value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); + + float o = (float) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, 2.0f); + assertEquals(1.0f, o, "getAndSetAcquire float"); + float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(2.0f, x, "getAndSetAcquire float value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); + + float o = (float) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, 2.0f); + assertEquals(1.0f, o, "getAndSetRelease float"); + float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(2.0f, x, "getAndSetRelease float value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, 1.0f); @@ -504,7 +524,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(1.0f, x, "failing weakCompareAndSetRe float value"); + assertEquals(1.0f, x, "failing weakCompareAndSet float value"); } // Compare set and get @@ -517,7 +537,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(2.0f, x, "getAndSet float value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(1.0f); @@ -527,7 +546,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(2.0f, x, "getAndSetAcquire float value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(1.0f); @@ -721,10 +739,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 1.0f, 3.0f); - assertEquals(success, false, "failing weakCompareAndSetAcquire float"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 1.0f, 3.0f); + assertEquals(success, false, "failing weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(2.0f, x, "failing weakCompareAndSetAcquire float value"); + assertEquals(2.0f, x, "failing weakCompareAndSetRelease float value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java index 8960ae124079..e260b50267d9 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessInt */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles h // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); + int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 0x89ABCDEF); assertEquals(0x01234567, o, "getAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(0x89ABCDEF, x, "getAndSet int value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); + + int o = (int) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, 0x89ABCDEF); + assertEquals(0x01234567, o, "getAndSetAcquire int"); + int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); + + int o = (int) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, 0x89ABCDEF); + assertEquals(0x01234567, o, "getAndSetRelease int"); + int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(0x89ABCDEF, x, "getAndSetRelease int value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, 0x01234567); @@ -582,7 +602,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(0x01234567, x, "failing weakCompareAndSetRe int value"); + assertEquals(0x01234567, x, "failing weakCompareAndSet int value"); } // Compare set and get @@ -595,7 +615,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(0x89ABCDEF, x, "getAndSet int value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(0x01234567); @@ -605,7 +624,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(0x89ABCDEF, x, "getAndSetAcquire int value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(0x01234567); @@ -877,10 +895,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x01234567, 0xCAFEBABE); - assertEquals(success, false, "failing weakCompareAndSetAcquire int"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 0x01234567, 0xCAFEBABE); + assertEquals(success, false, "failing weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetAcquire int value"); + assertEquals(0x89ABCDEF, x, "failing weakCompareAndSetRelease int value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java index cc6f2e729891..942ad2c38c11 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessLong */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); + long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 0xCAFEBABECAFEBABEL); assertEquals(0x0123456789ABCDEFL, o, "getAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); + + long o = (long) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetAcquire long"); + long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); + + long o = (long) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, 0xCAFEBABECAFEBABEL); + assertEquals(0x0123456789ABCDEFL, o, "getAndSetRelease long"); + long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetRelease long value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, 0x0123456789ABCDEFL); @@ -582,7 +602,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSetRe long value"); + assertEquals(0x0123456789ABCDEFL, x, "failing weakCompareAndSet long value"); } // Compare set and get @@ -595,7 +615,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSet long value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); @@ -605,7 +624,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(0xCAFEBABECAFEBABEL, x, "getAndSetAcquire long value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(0x0123456789ABCDEFL); @@ -877,10 +895,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); - assertEquals(success, false, "failing weakCompareAndSetAcquire long"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xDEADBEEFDEADBEEFL); + assertEquals(success, false, "failing weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetAcquire long value"); + assertEquals(0xCAFEBABECAFEBABEL, x, "failing weakCompareAndSetRelease long value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java index c9fc8fc1b6a3..aeb2d8495941 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessNullRestrictedValue.java @@ -28,8 +28,8 @@ * @enablePreview * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessNullRestrictedValue */ @@ -309,12 +309,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessNullRestrictedValue // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSet NullRestrictedValue"); NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetAcquire NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854)); + + NullRestrictedValue o = (NullRestrictedValue) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, NullRestrictedValue.of((byte)-42,(short)1854)); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), o, "getAndSetRelease NullRestrictedValue"); + NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetRelease NullRestrictedValue value"); + } + } @@ -497,7 +517,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(NullRestrictedValue.of((byte)-42,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); assertEquals(success, false, "failing weakCompareAndSet NullRestrictedValue"); NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSetRe NullRestrictedValue value"); + assertEquals(NullRestrictedValue.of((byte)20,(short)1854), x, "failing weakCompareAndSet NullRestrictedValue value"); } // Compare set and get @@ -510,7 +530,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSet NullRestrictedValue value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); @@ -520,7 +539,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "getAndSetAcquire NullRestrictedValue value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(NullRestrictedValue.of((byte)20,(short)1854)); @@ -692,10 +710,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); - assertEquals(success, false, "failing weakCompareAndSetAcquire NullRestrictedValue"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)-31083)); + assertEquals(success, false, "failing weakCompareAndSetRelease NullRestrictedValue"); NullRestrictedValue x = (NullRestrictedValue) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetAcquire NullRestrictedValue value"); + assertEquals(NullRestrictedValue.of((byte)-42,(short)1854), x, "failing weakCompareAndSetRelease NullRestrictedValue value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java index c5db745cd280..5caacdaabc65 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessShort */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); + short o = (short) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, (short)0x4567); assertEquals((short)0x0123, o, "getAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals((short)0x4567, x, "getAndSet short value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); + + short o = (short) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, (short)0x4567); + assertEquals((short)0x0123, o, "getAndSetAcquire short"); + short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals((short)0x4567, x, "getAndSetAcquire short value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); + + short o = (short) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, (short)0x4567); + assertEquals((short)0x0123, o, "getAndSetRelease short"); + short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals((short)0x4567, x, "getAndSetRelease short value"); + } + // get and add, add and get { hs.get(TestAccessMode.SET).invokeExact(recv, (short)0x0123); @@ -582,7 +602,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals((short)0x0123, x, "failing weakCompareAndSetRe short value"); + assertEquals((short)0x0123, x, "failing weakCompareAndSet short value"); } // Compare set and get @@ -595,7 +615,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals((short)0x4567, x, "getAndSet short value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); @@ -605,7 +624,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals((short)0x4567, x, "getAndSetAcquire short value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact((short)0x0123); @@ -877,10 +895,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (short)0x0123, (short)0x89AB); - assertEquals(success, false, "failing weakCompareAndSetAcquire short"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, (short)0x0123, (short)0x89AB); + assertEquals(success, false, "failing weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals((short)0x4567, x, "failing weakCompareAndSetAcquire short value"); + assertEquals((short)0x4567, x, "failing weakCompareAndSetRelease short value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java index f19fc8f631a4..2a3c2b31f852 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java @@ -25,8 +25,8 @@ /* * @test - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessString */ @@ -294,12 +294,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handle // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, "foo"); + String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "bar"); assertEquals("foo", o, "getAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals("bar", x, "getAndSet String value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, "foo"); + + String o = (String) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, "bar"); + assertEquals("foo", o, "getAndSetAcquire String"); + String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals("bar", x, "getAndSetAcquire String value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, "foo"); + + String o = (String) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, "bar"); + assertEquals("foo", o, "getAndSetRelease String"); + String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals("bar", x, "getAndSetRelease String value"); + } + } @@ -482,7 +502,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals("foo", x, "failing weakCompareAndSetRe String value"); + assertEquals("foo", x, "failing weakCompareAndSet String value"); } // Compare set and get @@ -495,7 +515,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals("bar", x, "getAndSet String value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact("foo"); @@ -505,7 +524,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals("bar", x, "getAndSetAcquire String value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact("foo"); @@ -677,10 +695,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, "foo", "baz"); - assertEquals(success, false, "failing weakCompareAndSetAcquire String"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, "foo", "baz"); + assertEquals(success, false, "failing weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals("bar", x, "failing weakCompareAndSetAcquire String value"); + assertEquals("bar", x, "failing weakCompareAndSetRelease String value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java index 32846afa5230..e13326927bf7 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java @@ -28,8 +28,8 @@ * @enablePreview * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccessValue */ @@ -297,12 +297,32 @@ static void testInstanceField(VarHandleTestMethodHandleAccessValue recv, Handles // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, Value.getInstance(10)); + Value o = (Value) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, Value.getInstance(20)); assertEquals(Value.getInstance(10), o, "getAndSet Value"); Value x = (Value) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals(Value.getInstance(20), x, "getAndSet Value value"); } + { + hs.get(TestAccessMode.SET).invokeExact(recv, Value.getInstance(10)); + + Value o = (Value) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, Value.getInstance(20)); + assertEquals(Value.getInstance(10), o, "getAndSetAcquire Value"); + Value x = (Value) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(Value.getInstance(20), x, "getAndSetAcquire Value value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, Value.getInstance(10)); + + Value o = (Value) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, Value.getInstance(20)); + assertEquals(Value.getInstance(10), o, "getAndSetRelease Value"); + Value x = (Value) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals(Value.getInstance(20), x, "getAndSetRelease Value value"); + } + } @@ -485,7 +505,7 @@ static void testStaticField(Handles hs) throws Throwable { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(Value.getInstance(20), Value.getInstance(30)); assertEquals(success, false, "failing weakCompareAndSet Value"); Value x = (Value) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals(Value.getInstance(10), x, "failing weakCompareAndSetRe Value value"); + assertEquals(Value.getInstance(10), x, "failing weakCompareAndSet Value value"); } // Compare set and get @@ -498,7 +518,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(Value.getInstance(20), x, "getAndSet Value value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(Value.getInstance(10)); @@ -508,7 +527,6 @@ static void testStaticField(Handles hs) throws Throwable { assertEquals(Value.getInstance(20), x, "getAndSetAcquire Value value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact(Value.getInstance(10)); @@ -680,10 +698,10 @@ static void testArray(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, Value.getInstance(10), Value.getInstance(30)); - assertEquals(success, false, "failing weakCompareAndSetAcquire Value"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, Value.getInstance(10), Value.getInstance(30)); + assertEquals(success, false, "failing weakCompareAndSetRelease Value"); Value x = (Value) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals(Value.getInstance(20), x, "failing weakCompareAndSetAcquire Value value"); + assertEquals(Value.getInstance(20), x, "failing weakCompareAndSetRelease Value value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java index d4413f0ab961..27a4eef9ad2a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeBoolean.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // actual reference class boolean x = (boolean) vh.compareAndExchange(recv, true, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.compareAndExchange(0, true, true); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // actual reference class boolean x = (boolean) vh.compareAndExchangeAcquire(recv, true, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.compareAndExchangeAcquire(0, true, true); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // actual reference class boolean x = (boolean) vh.compareAndExchangeRelease(recv, true, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.compareAndExchangeRelease(0, true, true); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndSet(0, true); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndSetAcquire(0, true); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndSetRelease(0, true); }); // Incorrect return type @@ -661,7 +661,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseOr(0, true); }); // Incorrect return type @@ -691,7 +691,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseOrAcquire(0, true); }); // Incorrect return type @@ -716,27 +716,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) vh.getAndBitwiseOrRelease(null, true); }); checkCCE(() -> { // receiver reference class - boolean x = (boolean) vh.getAndBitwiseOr(Void.class, true); + boolean x = (boolean) vh.getAndBitwiseOrRelease(Void.class, true); }); checkWMTE(() -> { // value reference class - boolean x = (boolean) vh.getAndBitwiseOr(recv, Void.class); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - boolean x = (boolean) vh.getAndBitwiseOr(0, true); + checkWMTE(() -> { // receiver primitive class + boolean x = (boolean) vh.getAndBitwiseOrRelease(0, true); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, true); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, true); }); checkWMTE(() -> { // primitive class - int x = (int) vh.getAndBitwiseOr(recv, true); + int x = (int) vh.getAndBitwiseOrRelease(recv, true); }); // Incorrect arity checkWMTE(() -> { // 0 - boolean x = (boolean) vh.getAndBitwiseOr(); + boolean x = (boolean) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - boolean x = (boolean) vh.getAndBitwiseOr(recv, true, Void.class); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, true, Void.class); }); @@ -751,7 +751,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseAnd(0, true); }); // Incorrect return type @@ -781,7 +781,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseAndAcquire(0, true); }); // Incorrect return type @@ -806,27 +806,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) vh.getAndBitwiseAndRelease(null, true); }); checkCCE(() -> { // receiver reference class - boolean x = (boolean) vh.getAndBitwiseAnd(Void.class, true); + boolean x = (boolean) vh.getAndBitwiseAndRelease(Void.class, true); }); checkWMTE(() -> { // value reference class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, Void.class); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(0, true); + checkWMTE(() -> { // receiver primitive class + boolean x = (boolean) vh.getAndBitwiseAndRelease(0, true); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, true); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, true); }); checkWMTE(() -> { // primitive class - int x = (int) vh.getAndBitwiseAnd(recv, true); + int x = (int) vh.getAndBitwiseAndRelease(recv, true); }); // Incorrect arity checkWMTE(() -> { // 0 - boolean x = (boolean) vh.getAndBitwiseAnd(); + boolean x = (boolean) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - boolean x = (boolean) vh.getAndBitwiseAnd(recv, true, Void.class); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, true, Void.class); }); @@ -841,7 +841,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseXor(0, true); }); // Incorrect return type @@ -871,7 +871,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) vh.getAndBitwiseXorAcquire(0, true); }); // Incorrect return type @@ -896,27 +896,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) vh.getAndBitwiseXorRelease(null, true); }); checkCCE(() -> { // receiver reference class - boolean x = (boolean) vh.getAndBitwiseXor(Void.class, true); + boolean x = (boolean) vh.getAndBitwiseXorRelease(Void.class, true); }); checkWMTE(() -> { // value reference class - boolean x = (boolean) vh.getAndBitwiseXor(recv, Void.class); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - boolean x = (boolean) vh.getAndBitwiseXor(0, true); + checkWMTE(() -> { // receiver primitive class + boolean x = (boolean) vh.getAndBitwiseXorRelease(0, true); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, true); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, true); }); checkWMTE(() -> { // primitive class - int x = (int) vh.getAndBitwiseXor(recv, true); + int x = (int) vh.getAndBitwiseXorRelease(recv, true); }); // Incorrect arity checkWMTE(() -> { // 0 - boolean x = (boolean) vh.getAndBitwiseXor(); + boolean x = (boolean) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - boolean x = (boolean) vh.getAndBitwiseXor(recv, true, Void.class); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, true, Void.class); }); } @@ -1034,7 +1034,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeBoolean.class, boolean.class, Class.class)). invokeExact(recv, true, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) hs.get(am, methodType(boolean.class, int.class , boolean.class, boolean.class)). invokeExact(0, true, true); }); @@ -1071,7 +1071,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeBoolean.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) hs.get(am, methodType(boolean.class, int.class, boolean.class)). invokeExact(0, true); }); @@ -1109,7 +1109,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeBoolean recv boolean x = (boolean) hs.get(am, methodType(boolean.class, VarHandleTestMethodTypeBoolean.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class boolean x = (boolean) hs.get(am, methodType(boolean.class, int.class, boolean.class)). invokeExact(0, true); }); @@ -1507,7 +1507,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseOrRelease(Void.class); @@ -1570,7 +1570,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseAndRelease(Void.class); @@ -1633,7 +1633,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndBitwiseXorRelease(Void.class); @@ -2287,7 +2287,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class boolean x = (boolean) vh.getAndSet(0, 0, true); }); checkWMTE(() -> { // index reference class @@ -2320,7 +2320,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class boolean x = (boolean) vh.getAndSetAcquire(0, 0, true); }); checkWMTE(() -> { // index reference class @@ -2353,7 +2353,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class boolean x = (boolean) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class boolean x = (boolean) vh.getAndSetRelease(0, 0, true); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java index 2abb22a65ae6..64036c334898 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeByte.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // actual reference class byte x = (byte) vh.compareAndExchange(recv, (byte)0x01, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.compareAndExchange(0, (byte)0x01, (byte)0x01); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // actual reference class byte x = (byte) vh.compareAndExchangeAcquire(recv, (byte)0x01, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.compareAndExchangeAcquire(0, (byte)0x01, (byte)0x01); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // actual reference class byte x = (byte) vh.compareAndExchangeRelease(recv, (byte)0x01, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.compareAndExchangeRelease(0, (byte)0x01, (byte)0x01); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndSet(0, (byte)0x01); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndSetAcquire(0, (byte)0x01); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndSetRelease(0, (byte)0x01); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndAdd(0, (byte)0x01); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndAddAcquire(0, (byte)0x01); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndAddRelease(0, (byte)0x01); }); // Incorrect return type @@ -747,7 +747,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseOr(0, (byte)0x01); }); // Incorrect return type @@ -777,7 +777,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseOrAcquire(0, (byte)0x01); }); // Incorrect return type @@ -802,27 +802,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V byte x = (byte) vh.getAndBitwiseOrRelease(null, (byte)0x01); }); checkCCE(() -> { // receiver reference class - byte x = (byte) vh.getAndBitwiseOr(Void.class, (byte)0x01); + byte x = (byte) vh.getAndBitwiseOrRelease(Void.class, (byte)0x01); }); checkWMTE(() -> { // value reference class - byte x = (byte) vh.getAndBitwiseOr(recv, Void.class); + byte x = (byte) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - byte x = (byte) vh.getAndBitwiseOr(0, (byte)0x01); + checkWMTE(() -> { // receiver primitive class + byte x = (byte) vh.getAndBitwiseOrRelease(0, (byte)0x01); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, (byte)0x01); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, (byte)0x01); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseOr(recv, (byte)0x01); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, (byte)0x01); }); // Incorrect arity checkWMTE(() -> { // 0 - byte x = (byte) vh.getAndBitwiseOr(); + byte x = (byte) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - byte x = (byte) vh.getAndBitwiseOr(recv, (byte)0x01, Void.class); + byte x = (byte) vh.getAndBitwiseOrRelease(recv, (byte)0x01, Void.class); }); @@ -837,7 +837,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseAnd(0, (byte)0x01); }); // Incorrect return type @@ -867,7 +867,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseAndAcquire(0, (byte)0x01); }); // Incorrect return type @@ -892,27 +892,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V byte x = (byte) vh.getAndBitwiseAndRelease(null, (byte)0x01); }); checkCCE(() -> { // receiver reference class - byte x = (byte) vh.getAndBitwiseAnd(Void.class, (byte)0x01); + byte x = (byte) vh.getAndBitwiseAndRelease(Void.class, (byte)0x01); }); checkWMTE(() -> { // value reference class - byte x = (byte) vh.getAndBitwiseAnd(recv, Void.class); + byte x = (byte) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - byte x = (byte) vh.getAndBitwiseAnd(0, (byte)0x01); + checkWMTE(() -> { // receiver primitive class + byte x = (byte) vh.getAndBitwiseAndRelease(0, (byte)0x01); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, (byte)0x01); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, (byte)0x01); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, (byte)0x01); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, (byte)0x01); }); // Incorrect arity checkWMTE(() -> { // 0 - byte x = (byte) vh.getAndBitwiseAnd(); + byte x = (byte) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - byte x = (byte) vh.getAndBitwiseAnd(recv, (byte)0x01, Void.class); + byte x = (byte) vh.getAndBitwiseAndRelease(recv, (byte)0x01, Void.class); }); @@ -927,7 +927,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseXor(0, (byte)0x01); }); // Incorrect return type @@ -957,7 +957,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) vh.getAndBitwiseXorAcquire(0, (byte)0x01); }); // Incorrect return type @@ -982,27 +982,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, V byte x = (byte) vh.getAndBitwiseXorRelease(null, (byte)0x01); }); checkCCE(() -> { // receiver reference class - byte x = (byte) vh.getAndBitwiseXor(Void.class, (byte)0x01); + byte x = (byte) vh.getAndBitwiseXorRelease(Void.class, (byte)0x01); }); checkWMTE(() -> { // value reference class - byte x = (byte) vh.getAndBitwiseXor(recv, Void.class); + byte x = (byte) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - byte x = (byte) vh.getAndBitwiseXor(0, (byte)0x01); + checkWMTE(() -> { // receiver primitive class + byte x = (byte) vh.getAndBitwiseXorRelease(0, (byte)0x01); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, (byte)0x01); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, (byte)0x01); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseXor(recv, (byte)0x01); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, (byte)0x01); }); // Incorrect arity checkWMTE(() -> { // 0 - byte x = (byte) vh.getAndBitwiseXor(); + byte x = (byte) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - byte x = (byte) vh.getAndBitwiseXor(recv, (byte)0x01, Void.class); + byte x = (byte) vh.getAndBitwiseXorRelease(recv, (byte)0x01, Void.class); }); } @@ -1120,7 +1120,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, H byte x = (byte) hs.get(am, methodType(byte.class, VarHandleTestMethodTypeByte.class, byte.class, Class.class)). invokeExact(recv, (byte)0x01, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) hs.get(am, methodType(byte.class, int.class , byte.class, byte.class)). invokeExact(0, (byte)0x01, (byte)0x01); }); @@ -1157,7 +1157,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, H byte x = (byte) hs.get(am, methodType(byte.class, VarHandleTestMethodTypeByte.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) hs.get(am, methodType(byte.class, int.class, byte.class)). invokeExact(0, (byte)0x01); }); @@ -1194,7 +1194,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, H byte x = (byte) hs.get(am, methodType(byte.class, VarHandleTestMethodTypeByte.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) hs.get(am, methodType(byte.class, int.class, byte.class)). invokeExact(0, (byte)0x01); }); @@ -1231,7 +1231,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeByte recv, H byte x = (byte) hs.get(am, methodType(byte.class, VarHandleTestMethodTypeByte.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class byte x = (byte) hs.get(am, methodType(byte.class, int.class, byte.class)). invokeExact(0, (byte)0x01); }); @@ -1690,7 +1690,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseOrRelease(Void.class); @@ -1753,7 +1753,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseAndRelease(Void.class); @@ -1816,7 +1816,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndBitwiseXorRelease(Void.class); @@ -2495,7 +2495,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class byte x = (byte) vh.getAndSet(0, 0, (byte)0x01); }); checkWMTE(() -> { // index reference class @@ -2528,7 +2528,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class byte x = (byte) vh.getAndSetAcquire(0, 0, (byte)0x01); }); checkWMTE(() -> { // index reference class @@ -2561,7 +2561,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class byte x = (byte) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class byte x = (byte) vh.getAndSetRelease(0, 0, (byte)0x01); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java index 4eaf3d5c69fd..b20d86185bf2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeChar.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // actual reference class char x = (char) vh.compareAndExchange(recv, '\u0123', Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.compareAndExchange(0, '\u0123', '\u0123'); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // actual reference class char x = (char) vh.compareAndExchangeAcquire(recv, '\u0123', Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.compareAndExchangeAcquire(0, '\u0123', '\u0123'); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // actual reference class char x = (char) vh.compareAndExchangeRelease(recv, '\u0123', Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.compareAndExchangeRelease(0, '\u0123', '\u0123'); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndSet(0, '\u0123'); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndSetAcquire(0, '\u0123'); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndSetRelease(0, '\u0123'); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndAdd(0, '\u0123'); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndAddAcquire(0, '\u0123'); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndAddRelease(0, '\u0123'); }); // Incorrect return type @@ -747,7 +747,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseOr(0, '\u0123'); }); // Incorrect return type @@ -777,7 +777,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseOrAcquire(0, '\u0123'); }); // Incorrect return type @@ -802,27 +802,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V char x = (char) vh.getAndBitwiseOrRelease(null, '\u0123'); }); checkCCE(() -> { // receiver reference class - char x = (char) vh.getAndBitwiseOr(Void.class, '\u0123'); + char x = (char) vh.getAndBitwiseOrRelease(Void.class, '\u0123'); }); checkWMTE(() -> { // value reference class - char x = (char) vh.getAndBitwiseOr(recv, Void.class); + char x = (char) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - char x = (char) vh.getAndBitwiseOr(0, '\u0123'); + checkWMTE(() -> { // receiver primitive class + char x = (char) vh.getAndBitwiseOrRelease(0, '\u0123'); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, '\u0123'); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, '\u0123'); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseOr(recv, '\u0123'); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, '\u0123'); }); // Incorrect arity checkWMTE(() -> { // 0 - char x = (char) vh.getAndBitwiseOr(); + char x = (char) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - char x = (char) vh.getAndBitwiseOr(recv, '\u0123', Void.class); + char x = (char) vh.getAndBitwiseOrRelease(recv, '\u0123', Void.class); }); @@ -837,7 +837,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseAnd(0, '\u0123'); }); // Incorrect return type @@ -867,7 +867,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseAndAcquire(0, '\u0123'); }); // Incorrect return type @@ -892,27 +892,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V char x = (char) vh.getAndBitwiseAndRelease(null, '\u0123'); }); checkCCE(() -> { // receiver reference class - char x = (char) vh.getAndBitwiseAnd(Void.class, '\u0123'); + char x = (char) vh.getAndBitwiseAndRelease(Void.class, '\u0123'); }); checkWMTE(() -> { // value reference class - char x = (char) vh.getAndBitwiseAnd(recv, Void.class); + char x = (char) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - char x = (char) vh.getAndBitwiseAnd(0, '\u0123'); + checkWMTE(() -> { // receiver primitive class + char x = (char) vh.getAndBitwiseAndRelease(0, '\u0123'); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, '\u0123'); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, '\u0123'); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, '\u0123'); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, '\u0123'); }); // Incorrect arity checkWMTE(() -> { // 0 - char x = (char) vh.getAndBitwiseAnd(); + char x = (char) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - char x = (char) vh.getAndBitwiseAnd(recv, '\u0123', Void.class); + char x = (char) vh.getAndBitwiseAndRelease(recv, '\u0123', Void.class); }); @@ -927,7 +927,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseXor(0, '\u0123'); }); // Incorrect return type @@ -957,7 +957,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) vh.getAndBitwiseXorAcquire(0, '\u0123'); }); // Incorrect return type @@ -982,27 +982,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, V char x = (char) vh.getAndBitwiseXorRelease(null, '\u0123'); }); checkCCE(() -> { // receiver reference class - char x = (char) vh.getAndBitwiseXor(Void.class, '\u0123'); + char x = (char) vh.getAndBitwiseXorRelease(Void.class, '\u0123'); }); checkWMTE(() -> { // value reference class - char x = (char) vh.getAndBitwiseXor(recv, Void.class); + char x = (char) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - char x = (char) vh.getAndBitwiseXor(0, '\u0123'); + checkWMTE(() -> { // receiver primitive class + char x = (char) vh.getAndBitwiseXorRelease(0, '\u0123'); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, '\u0123'); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, '\u0123'); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseXor(recv, '\u0123'); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, '\u0123'); }); // Incorrect arity checkWMTE(() -> { // 0 - char x = (char) vh.getAndBitwiseXor(); + char x = (char) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - char x = (char) vh.getAndBitwiseXor(recv, '\u0123', Void.class); + char x = (char) vh.getAndBitwiseXorRelease(recv, '\u0123', Void.class); }); } @@ -1120,7 +1120,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, H char x = (char) hs.get(am, methodType(char.class, VarHandleTestMethodTypeChar.class, char.class, Class.class)). invokeExact(recv, '\u0123', Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) hs.get(am, methodType(char.class, int.class , char.class, char.class)). invokeExact(0, '\u0123', '\u0123'); }); @@ -1157,7 +1157,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, H char x = (char) hs.get(am, methodType(char.class, VarHandleTestMethodTypeChar.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) hs.get(am, methodType(char.class, int.class, char.class)). invokeExact(0, '\u0123'); }); @@ -1194,7 +1194,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, H char x = (char) hs.get(am, methodType(char.class, VarHandleTestMethodTypeChar.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) hs.get(am, methodType(char.class, int.class, char.class)). invokeExact(0, '\u0123'); }); @@ -1231,7 +1231,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeChar recv, H char x = (char) hs.get(am, methodType(char.class, VarHandleTestMethodTypeChar.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class char x = (char) hs.get(am, methodType(char.class, int.class, char.class)). invokeExact(0, '\u0123'); }); @@ -1690,7 +1690,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseOrRelease(Void.class); @@ -1753,7 +1753,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseAndRelease(Void.class); @@ -1816,7 +1816,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class char x = (char) vh.getAndBitwiseXorRelease(Void.class); @@ -2495,7 +2495,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class char x = (char) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class char x = (char) vh.getAndSet(0, 0, '\u0123'); }); checkWMTE(() -> { // index reference class @@ -2528,7 +2528,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class char x = (char) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class char x = (char) vh.getAndSetAcquire(0, 0, '\u0123'); }); checkWMTE(() -> { // index reference class @@ -2561,7 +2561,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class char x = (char) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class char x = (char) vh.getAndSetRelease(0, 0, '\u0123'); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java index 995b7008a468..75cc8fab5cba 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeDouble.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // actual reference class double x = (double) vh.compareAndExchange(recv, 1.0d, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.compareAndExchange(0, 1.0d, 1.0d); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // actual reference class double x = (double) vh.compareAndExchangeAcquire(recv, 1.0d, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.compareAndExchangeAcquire(0, 1.0d, 1.0d); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // actual reference class double x = (double) vh.compareAndExchangeRelease(recv, 1.0d, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.compareAndExchangeRelease(0, 1.0d, 1.0d); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndSet(0, 1.0d); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndSetAcquire(0, 1.0d); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndSetRelease(0, 1.0d); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndAdd(0, 1.0d); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndAddAcquire(0, 1.0d); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, checkWMTE(() -> { // value reference class double x = (double) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) vh.getAndAddRelease(0, 1.0d); }); // Incorrect return type @@ -852,7 +852,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, double x = (double) hs.get(am, methodType(double.class, VarHandleTestMethodTypeDouble.class, double.class, Class.class)). invokeExact(recv, 1.0d, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) hs.get(am, methodType(double.class, int.class , double.class, double.class)). invokeExact(0, 1.0d, 1.0d); }); @@ -889,7 +889,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, double x = (double) hs.get(am, methodType(double.class, VarHandleTestMethodTypeDouble.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) hs.get(am, methodType(double.class, int.class, double.class)). invokeExact(0, 1.0d); }); @@ -926,7 +926,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeDouble recv, double x = (double) hs.get(am, methodType(double.class, VarHandleTestMethodTypeDouble.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class double x = (double) hs.get(am, methodType(double.class, int.class, double.class)). invokeExact(0, 1.0d); }); @@ -1979,7 +1979,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class double x = (double) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class double x = (double) vh.getAndSet(0, 0, 1.0d); }); checkWMTE(() -> { // index reference class @@ -2012,7 +2012,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class double x = (double) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class double x = (double) vh.getAndSetAcquire(0, 0, 1.0d); }); checkWMTE(() -> { // index reference class @@ -2045,7 +2045,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class double x = (double) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class double x = (double) vh.getAndSetRelease(0, 0, 1.0d); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java index 5ab921168859..db786f136729 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeFloat.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // actual reference class float x = (float) vh.compareAndExchange(recv, 1.0f, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.compareAndExchange(0, 1.0f, 1.0f); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // actual reference class float x = (float) vh.compareAndExchangeAcquire(recv, 1.0f, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.compareAndExchangeAcquire(0, 1.0f, 1.0f); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // actual reference class float x = (float) vh.compareAndExchangeRelease(recv, 1.0f, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.compareAndExchangeRelease(0, 1.0f, 1.0f); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndSet(0, 1.0f); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndSetAcquire(0, 1.0f); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndSetRelease(0, 1.0f); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndAdd(0, 1.0f); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndAddAcquire(0, 1.0f); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, checkWMTE(() -> { // value reference class float x = (float) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) vh.getAndAddRelease(0, 1.0f); }); // Incorrect return type @@ -852,7 +852,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, float x = (float) hs.get(am, methodType(float.class, VarHandleTestMethodTypeFloat.class, float.class, Class.class)). invokeExact(recv, 1.0f, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) hs.get(am, methodType(float.class, int.class , float.class, float.class)). invokeExact(0, 1.0f, 1.0f); }); @@ -889,7 +889,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, float x = (float) hs.get(am, methodType(float.class, VarHandleTestMethodTypeFloat.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) hs.get(am, methodType(float.class, int.class, float.class)). invokeExact(0, 1.0f); }); @@ -926,7 +926,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeFloat recv, float x = (float) hs.get(am, methodType(float.class, VarHandleTestMethodTypeFloat.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class float x = (float) hs.get(am, methodType(float.class, int.class, float.class)). invokeExact(0, 1.0f); }); @@ -1979,7 +1979,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class float x = (float) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class float x = (float) vh.getAndSet(0, 0, 1.0f); }); checkWMTE(() -> { // index reference class @@ -2012,7 +2012,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class float x = (float) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class float x = (float) vh.getAndSetAcquire(0, 0, 1.0f); }); checkWMTE(() -> { // index reference class @@ -2045,7 +2045,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class float x = (float) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class float x = (float) vh.getAndSetRelease(0, 0, 1.0f); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java index fd8745edbf01..09fc9c005241 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // actual reference class int x = (int) vh.compareAndExchange(recv, 0x01234567, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.compareAndExchange(0, 0x01234567, 0x01234567); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // actual reference class int x = (int) vh.compareAndExchangeAcquire(recv, 0x01234567, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.compareAndExchangeAcquire(0, 0x01234567, 0x01234567); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // actual reference class int x = (int) vh.compareAndExchangeRelease(recv, 0x01234567, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.compareAndExchangeRelease(0, 0x01234567, 0x01234567); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndSet(0, 0x01234567); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndSetAcquire(0, 0x01234567); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndSetRelease(0, 0x01234567); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndAdd(0, 0x01234567); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndAddAcquire(0, 0x01234567); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndAddRelease(0, 0x01234567); }); // Incorrect return type @@ -747,7 +747,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseOr(0, 0x01234567); }); // Incorrect return type @@ -777,7 +777,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseOrAcquire(0, 0x01234567); }); // Incorrect return type @@ -802,27 +802,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va int x = (int) vh.getAndBitwiseOrRelease(null, 0x01234567); }); checkCCE(() -> { // receiver reference class - int x = (int) vh.getAndBitwiseOr(Void.class, 0x01234567); + int x = (int) vh.getAndBitwiseOrRelease(Void.class, 0x01234567); }); checkWMTE(() -> { // value reference class - int x = (int) vh.getAndBitwiseOr(recv, Void.class); + int x = (int) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - int x = (int) vh.getAndBitwiseOr(0, 0x01234567); + checkWMTE(() -> { // receiver primitive class + int x = (int) vh.getAndBitwiseOrRelease(0, 0x01234567); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, 0x01234567); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, 0x01234567); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseOr(recv, 0x01234567); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, 0x01234567); }); // Incorrect arity checkWMTE(() -> { // 0 - int x = (int) vh.getAndBitwiseOr(); + int x = (int) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - int x = (int) vh.getAndBitwiseOr(recv, 0x01234567, Void.class); + int x = (int) vh.getAndBitwiseOrRelease(recv, 0x01234567, Void.class); }); @@ -837,7 +837,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseAnd(0, 0x01234567); }); // Incorrect return type @@ -867,7 +867,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseAndAcquire(0, 0x01234567); }); // Incorrect return type @@ -892,27 +892,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va int x = (int) vh.getAndBitwiseAndRelease(null, 0x01234567); }); checkCCE(() -> { // receiver reference class - int x = (int) vh.getAndBitwiseAnd(Void.class, 0x01234567); + int x = (int) vh.getAndBitwiseAndRelease(Void.class, 0x01234567); }); checkWMTE(() -> { // value reference class - int x = (int) vh.getAndBitwiseAnd(recv, Void.class); + int x = (int) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - int x = (int) vh.getAndBitwiseAnd(0, 0x01234567); + checkWMTE(() -> { // receiver primitive class + int x = (int) vh.getAndBitwiseAndRelease(0, 0x01234567); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, 0x01234567); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, 0x01234567); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, 0x01234567); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, 0x01234567); }); // Incorrect arity checkWMTE(() -> { // 0 - int x = (int) vh.getAndBitwiseAnd(); + int x = (int) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - int x = (int) vh.getAndBitwiseAnd(recv, 0x01234567, Void.class); + int x = (int) vh.getAndBitwiseAndRelease(recv, 0x01234567, Void.class); }); @@ -927,7 +927,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseXor(0, 0x01234567); }); // Incorrect return type @@ -957,7 +957,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) vh.getAndBitwiseXorAcquire(0, 0x01234567); }); // Incorrect return type @@ -982,27 +982,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Va int x = (int) vh.getAndBitwiseXorRelease(null, 0x01234567); }); checkCCE(() -> { // receiver reference class - int x = (int) vh.getAndBitwiseXor(Void.class, 0x01234567); + int x = (int) vh.getAndBitwiseXorRelease(Void.class, 0x01234567); }); checkWMTE(() -> { // value reference class - int x = (int) vh.getAndBitwiseXor(recv, Void.class); + int x = (int) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - int x = (int) vh.getAndBitwiseXor(0, 0x01234567); + checkWMTE(() -> { // receiver primitive class + int x = (int) vh.getAndBitwiseXorRelease(0, 0x01234567); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, 0x01234567); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, 0x01234567); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseXor(recv, 0x01234567); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, 0x01234567); }); // Incorrect arity checkWMTE(() -> { // 0 - int x = (int) vh.getAndBitwiseXor(); + int x = (int) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - int x = (int) vh.getAndBitwiseXor(recv, 0x01234567, Void.class); + int x = (int) vh.getAndBitwiseXorRelease(recv, 0x01234567, Void.class); }); } @@ -1120,7 +1120,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Ha int x = (int) hs.get(am, methodType(int.class, VarHandleTestMethodTypeInt.class, int.class, Class.class)). invokeExact(recv, 0x01234567, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) hs.get(am, methodType(int.class, int.class , int.class, int.class)). invokeExact(0, 0x01234567, 0x01234567); }); @@ -1157,7 +1157,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Ha int x = (int) hs.get(am, methodType(int.class, VarHandleTestMethodTypeInt.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) hs.get(am, methodType(int.class, int.class, int.class)). invokeExact(0, 0x01234567); }); @@ -1194,7 +1194,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Ha int x = (int) hs.get(am, methodType(int.class, VarHandleTestMethodTypeInt.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) hs.get(am, methodType(int.class, int.class, int.class)). invokeExact(0, 0x01234567); }); @@ -1231,7 +1231,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeInt recv, Ha int x = (int) hs.get(am, methodType(int.class, VarHandleTestMethodTypeInt.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class int x = (int) hs.get(am, methodType(int.class, int.class, int.class)). invokeExact(0, 0x01234567); }); @@ -1690,7 +1690,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseOrRelease(Void.class); @@ -1753,7 +1753,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseAndRelease(Void.class); @@ -1816,7 +1816,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class int x = (int) vh.getAndBitwiseXorRelease(Void.class); @@ -2495,7 +2495,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class int x = (int) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class int x = (int) vh.getAndSet(0, 0, 0x01234567); }); checkWMTE(() -> { // index reference class @@ -2528,7 +2528,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class int x = (int) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class int x = (int) vh.getAndSetAcquire(0, 0, 0x01234567); }); checkWMTE(() -> { // index reference class @@ -2561,7 +2561,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class int x = (int) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class int x = (int) vh.getAndSetRelease(0, 0, 0x01234567); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java index 3a7acef97b4a..017735f10888 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // actual reference class long x = (long) vh.compareAndExchange(recv, 0x0123456789ABCDEFL, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.compareAndExchange(0, 0x0123456789ABCDEFL, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // actual reference class long x = (long) vh.compareAndExchangeAcquire(recv, 0x0123456789ABCDEFL, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.compareAndExchangeAcquire(0, 0x0123456789ABCDEFL, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // actual reference class long x = (long) vh.compareAndExchangeRelease(recv, 0x0123456789ABCDEFL, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.compareAndExchangeRelease(0, 0x0123456789ABCDEFL, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndSet(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndSetAcquire(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndSetRelease(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndAdd(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndAddAcquire(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndAddRelease(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -747,7 +747,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseOr(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -777,7 +777,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseOrAcquire(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -802,27 +802,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V long x = (long) vh.getAndBitwiseOrRelease(null, 0x0123456789ABCDEFL); }); checkCCE(() -> { // receiver reference class - long x = (long) vh.getAndBitwiseOr(Void.class, 0x0123456789ABCDEFL); + long x = (long) vh.getAndBitwiseOrRelease(Void.class, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // value reference class - long x = (long) vh.getAndBitwiseOr(recv, Void.class); + long x = (long) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - long x = (long) vh.getAndBitwiseOr(0, 0x0123456789ABCDEFL); + checkWMTE(() -> { // receiver primitive class + long x = (long) vh.getAndBitwiseOrRelease(0, 0x0123456789ABCDEFL); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, 0x0123456789ABCDEFL); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseOr(recv, 0x0123456789ABCDEFL); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, 0x0123456789ABCDEFL); }); // Incorrect arity checkWMTE(() -> { // 0 - long x = (long) vh.getAndBitwiseOr(); + long x = (long) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - long x = (long) vh.getAndBitwiseOr(recv, 0x0123456789ABCDEFL, Void.class); + long x = (long) vh.getAndBitwiseOrRelease(recv, 0x0123456789ABCDEFL, Void.class); }); @@ -837,7 +837,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseAnd(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -867,7 +867,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseAndAcquire(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -892,27 +892,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V long x = (long) vh.getAndBitwiseAndRelease(null, 0x0123456789ABCDEFL); }); checkCCE(() -> { // receiver reference class - long x = (long) vh.getAndBitwiseAnd(Void.class, 0x0123456789ABCDEFL); + long x = (long) vh.getAndBitwiseAndRelease(Void.class, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // value reference class - long x = (long) vh.getAndBitwiseAnd(recv, Void.class); + long x = (long) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - long x = (long) vh.getAndBitwiseAnd(0, 0x0123456789ABCDEFL); + checkWMTE(() -> { // receiver primitive class + long x = (long) vh.getAndBitwiseAndRelease(0, 0x0123456789ABCDEFL); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, 0x0123456789ABCDEFL); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, 0x0123456789ABCDEFL); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, 0x0123456789ABCDEFL); }); // Incorrect arity checkWMTE(() -> { // 0 - long x = (long) vh.getAndBitwiseAnd(); + long x = (long) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - long x = (long) vh.getAndBitwiseAnd(recv, 0x0123456789ABCDEFL, Void.class); + long x = (long) vh.getAndBitwiseAndRelease(recv, 0x0123456789ABCDEFL, Void.class); }); @@ -927,7 +927,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseXor(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -957,7 +957,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) vh.getAndBitwiseXorAcquire(0, 0x0123456789ABCDEFL); }); // Incorrect return type @@ -982,27 +982,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, V long x = (long) vh.getAndBitwiseXorRelease(null, 0x0123456789ABCDEFL); }); checkCCE(() -> { // receiver reference class - long x = (long) vh.getAndBitwiseXor(Void.class, 0x0123456789ABCDEFL); + long x = (long) vh.getAndBitwiseXorRelease(Void.class, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // value reference class - long x = (long) vh.getAndBitwiseXor(recv, Void.class); + long x = (long) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - long x = (long) vh.getAndBitwiseXor(0, 0x0123456789ABCDEFL); + checkWMTE(() -> { // receiver primitive class + long x = (long) vh.getAndBitwiseXorRelease(0, 0x0123456789ABCDEFL); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, 0x0123456789ABCDEFL); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseXor(recv, 0x0123456789ABCDEFL); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, 0x0123456789ABCDEFL); }); // Incorrect arity checkWMTE(() -> { // 0 - long x = (long) vh.getAndBitwiseXor(); + long x = (long) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - long x = (long) vh.getAndBitwiseXor(recv, 0x0123456789ABCDEFL, Void.class); + long x = (long) vh.getAndBitwiseXorRelease(recv, 0x0123456789ABCDEFL, Void.class); }); } @@ -1120,7 +1120,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, H long x = (long) hs.get(am, methodType(long.class, VarHandleTestMethodTypeLong.class, long.class, Class.class)). invokeExact(recv, 0x0123456789ABCDEFL, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) hs.get(am, methodType(long.class, int.class , long.class, long.class)). invokeExact(0, 0x0123456789ABCDEFL, 0x0123456789ABCDEFL); }); @@ -1157,7 +1157,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, H long x = (long) hs.get(am, methodType(long.class, VarHandleTestMethodTypeLong.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) hs.get(am, methodType(long.class, int.class, long.class)). invokeExact(0, 0x0123456789ABCDEFL); }); @@ -1194,7 +1194,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, H long x = (long) hs.get(am, methodType(long.class, VarHandleTestMethodTypeLong.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) hs.get(am, methodType(long.class, int.class, long.class)). invokeExact(0, 0x0123456789ABCDEFL); }); @@ -1231,7 +1231,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeLong recv, H long x = (long) hs.get(am, methodType(long.class, VarHandleTestMethodTypeLong.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class long x = (long) hs.get(am, methodType(long.class, int.class, long.class)). invokeExact(0, 0x0123456789ABCDEFL); }); @@ -1690,7 +1690,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseOrRelease(Void.class); @@ -1753,7 +1753,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseAndRelease(Void.class); @@ -1816,7 +1816,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class long x = (long) vh.getAndBitwiseXorRelease(Void.class); @@ -2495,7 +2495,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class long x = (long) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class long x = (long) vh.getAndSet(0, 0, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // index reference class @@ -2528,7 +2528,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class long x = (long) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class long x = (long) vh.getAndSetAcquire(0, 0, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // index reference class @@ -2561,7 +2561,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class long x = (long) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class long x = (long) vh.getAndSetRelease(0, 0, 0x0123456789ABCDEFL); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java index 900e58f0545d..9eb6af4baef4 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeNullRestrictedValue.java @@ -483,7 +483,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // actual reference class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchange(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -516,7 +516,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // actual reference class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeAcquire(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -549,7 +549,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // actual reference class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.compareAndExchangeRelease(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -579,7 +579,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(0, NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -608,7 +608,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(0, NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -637,7 +637,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(0, NullRestrictedValue.of((byte)20,(short)1854)); }); // Incorrect return type @@ -772,7 +772,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, NullRestrictedValue.class, Class.class)). invokeExact(recv, NullRestrictedValue.of((byte)20,(short)1854), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class , NullRestrictedValue.class, NullRestrictedValue.class)). invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854), NullRestrictedValue.of((byte)20,(short)1854)); }); @@ -809,7 +809,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeNullRestrict NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, VarHandleTestMethodTypeNullRestrictedValue.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class NullRestrictedValue x = (NullRestrictedValue) hs.get(am, methodType(NullRestrictedValue.class, int.class, NullRestrictedValue.class)). invokeExact(0, NullRestrictedValue.of((byte)20,(short)1854)); }); @@ -1777,7 +1777,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSet(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); }); checkWMTE(() -> { // index reference class @@ -1810,7 +1810,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetAcquire(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); }); checkWMTE(() -> { // index reference class @@ -1843,7 +1843,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class NullRestrictedValue x = (NullRestrictedValue) vh.getAndSetRelease(0, 0, NullRestrictedValue.of((byte)20,(short)1854)); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java index 2bd3fafbfd99..c2f9afe218a1 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeShort.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // actual reference class short x = (short) vh.compareAndExchange(recv, (short)0x0123, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.compareAndExchange(0, (short)0x0123, (short)0x0123); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // actual reference class short x = (short) vh.compareAndExchangeAcquire(recv, (short)0x0123, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.compareAndExchangeAcquire(0, (short)0x0123, (short)0x0123); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // actual reference class short x = (short) vh.compareAndExchangeRelease(recv, (short)0x0123, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.compareAndExchangeRelease(0, (short)0x0123, (short)0x0123); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndSet(0, (short)0x0123); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndSetAcquire(0, (short)0x0123); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndSetRelease(0, (short)0x0123); }); // Incorrect return type @@ -660,7 +660,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndAdd(0, (short)0x0123); }); // Incorrect return type @@ -689,7 +689,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndAddAcquire(0, (short)0x0123); }); // Incorrect return type @@ -718,7 +718,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndAddRelease(0, (short)0x0123); }); // Incorrect return type @@ -747,7 +747,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseOr(0, (short)0x0123); }); // Incorrect return type @@ -777,7 +777,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseOrAcquire(0, (short)0x0123); }); // Incorrect return type @@ -802,27 +802,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) vh.getAndBitwiseOrRelease(null, (short)0x0123); }); checkCCE(() -> { // receiver reference class - short x = (short) vh.getAndBitwiseOr(Void.class, (short)0x0123); + short x = (short) vh.getAndBitwiseOrRelease(Void.class, (short)0x0123); }); checkWMTE(() -> { // value reference class - short x = (short) vh.getAndBitwiseOr(recv, Void.class); + short x = (short) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - short x = (short) vh.getAndBitwiseOr(0, (short)0x0123); + checkWMTE(() -> { // receiver primitive class + short x = (short) vh.getAndBitwiseOrRelease(0, (short)0x0123); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, (short)0x0123); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, (short)0x0123); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseOr(recv, (short)0x0123); + boolean x = (boolean) vh.getAndBitwiseOrRelease(recv, (short)0x0123); }); // Incorrect arity checkWMTE(() -> { // 0 - short x = (short) vh.getAndBitwiseOr(); + short x = (short) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - short x = (short) vh.getAndBitwiseOr(recv, (short)0x0123, Void.class); + short x = (short) vh.getAndBitwiseOrRelease(recv, (short)0x0123, Void.class); }); @@ -837,7 +837,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseAnd(0, (short)0x0123); }); // Incorrect return type @@ -867,7 +867,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseAndAcquire(0, (short)0x0123); }); // Incorrect return type @@ -892,27 +892,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) vh.getAndBitwiseAndRelease(null, (short)0x0123); }); checkCCE(() -> { // receiver reference class - short x = (short) vh.getAndBitwiseAnd(Void.class, (short)0x0123); + short x = (short) vh.getAndBitwiseAndRelease(Void.class, (short)0x0123); }); checkWMTE(() -> { // value reference class - short x = (short) vh.getAndBitwiseAnd(recv, Void.class); + short x = (short) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - short x = (short) vh.getAndBitwiseAnd(0, (short)0x0123); + checkWMTE(() -> { // receiver primitive class + short x = (short) vh.getAndBitwiseAndRelease(0, (short)0x0123); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, (short)0x0123); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, (short)0x0123); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseAnd(recv, (short)0x0123); + boolean x = (boolean) vh.getAndBitwiseAndRelease(recv, (short)0x0123); }); // Incorrect arity checkWMTE(() -> { // 0 - short x = (short) vh.getAndBitwiseAnd(); + short x = (short) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - short x = (short) vh.getAndBitwiseAnd(recv, (short)0x0123, Void.class); + short x = (short) vh.getAndBitwiseAndRelease(recv, (short)0x0123, Void.class); }); @@ -927,7 +927,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseXor(0, (short)0x0123); }); // Incorrect return type @@ -957,7 +957,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) vh.getAndBitwiseXorAcquire(0, (short)0x0123); }); // Incorrect return type @@ -982,27 +982,27 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) vh.getAndBitwiseXorRelease(null, (short)0x0123); }); checkCCE(() -> { // receiver reference class - short x = (short) vh.getAndBitwiseXor(Void.class, (short)0x0123); + short x = (short) vh.getAndBitwiseXorRelease(Void.class, (short)0x0123); }); checkWMTE(() -> { // value reference class - short x = (short) vh.getAndBitwiseXor(recv, Void.class); + short x = (short) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - short x = (short) vh.getAndBitwiseXor(0, (short)0x0123); + checkWMTE(() -> { // receiver primitive class + short x = (short) vh.getAndBitwiseXorRelease(0, (short)0x0123); }); // Incorrect return type checkWMTE(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, (short)0x0123); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, (short)0x0123); }); checkWMTE(() -> { // primitive class - boolean x = (boolean) vh.getAndBitwiseXor(recv, (short)0x0123); + boolean x = (boolean) vh.getAndBitwiseXorRelease(recv, (short)0x0123); }); // Incorrect arity checkWMTE(() -> { // 0 - short x = (short) vh.getAndBitwiseXor(); + short x = (short) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - short x = (short) vh.getAndBitwiseXor(recv, (short)0x0123, Void.class); + short x = (short) vh.getAndBitwiseXorRelease(recv, (short)0x0123, Void.class); }); } @@ -1120,7 +1120,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) hs.get(am, methodType(short.class, VarHandleTestMethodTypeShort.class, short.class, Class.class)). invokeExact(recv, (short)0x0123, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) hs.get(am, methodType(short.class, int.class , short.class, short.class)). invokeExact(0, (short)0x0123, (short)0x0123); }); @@ -1157,7 +1157,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) hs.get(am, methodType(short.class, VarHandleTestMethodTypeShort.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) hs.get(am, methodType(short.class, int.class, short.class)). invokeExact(0, (short)0x0123); }); @@ -1194,7 +1194,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) hs.get(am, methodType(short.class, VarHandleTestMethodTypeShort.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) hs.get(am, methodType(short.class, int.class, short.class)). invokeExact(0, (short)0x0123); }); @@ -1231,7 +1231,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeShort recv, short x = (short) hs.get(am, methodType(short.class, VarHandleTestMethodTypeShort.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class short x = (short) hs.get(am, methodType(short.class, int.class, short.class)). invokeExact(0, (short)0x0123); }); @@ -1690,7 +1690,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseOrRelease(Void.class); @@ -1753,7 +1753,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseAndRelease(Void.class); @@ -1816,7 +1816,7 @@ static void testStaticFieldWrongMethodType(VarHandle vh) throws Throwable { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types checkWMTE(() -> { // value reference class short x = (short) vh.getAndBitwiseXorRelease(Void.class); @@ -2495,7 +2495,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class short x = (short) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class short x = (short) vh.getAndSet(0, 0, (short)0x0123); }); checkWMTE(() -> { // index reference class @@ -2528,7 +2528,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class short x = (short) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class short x = (short) vh.getAndSetAcquire(0, 0, (short)0x0123); }); checkWMTE(() -> { // index reference class @@ -2561,7 +2561,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkWMTE(() -> { // value reference class short x = (short) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class short x = (short) vh.getAndSetRelease(0, 0, (short)0x0123); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java index 49a601f38d4c..30c9c76c4b43 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java @@ -477,7 +477,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // actual reference class String x = (String) vh.compareAndExchange(recv, "foo", Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.compareAndExchange(0, "foo", "foo"); }); // Incorrect return type @@ -510,7 +510,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // actual reference class String x = (String) vh.compareAndExchangeAcquire(recv, "foo", Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.compareAndExchangeAcquire(0, "foo", "foo"); }); // Incorrect return type @@ -543,7 +543,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // actual reference class String x = (String) vh.compareAndExchangeRelease(recv, "foo", Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.compareAndExchangeRelease(0, "foo", "foo"); }); // Incorrect return type @@ -573,7 +573,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // value reference class String x = (String) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.getAndSet(0, "foo"); }); // Incorrect return type @@ -602,7 +602,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // value reference class String x = (String) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.getAndSetAcquire(0, "foo"); }); // Incorrect return type @@ -631,7 +631,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, checkCCE(() -> { // value reference class String x = (String) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) vh.getAndSetRelease(0, "foo"); }); // Incorrect return type @@ -766,7 +766,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, String x = (String) hs.get(am, methodType(String.class, VarHandleTestMethodTypeString.class, String.class, Class.class)). invokeExact(recv, "foo", Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) hs.get(am, methodType(String.class, int.class , String.class, String.class)). invokeExact(0, "foo", "foo"); }); @@ -803,7 +803,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeString recv, String x = (String) hs.get(am, methodType(String.class, VarHandleTestMethodTypeString.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class String x = (String) hs.get(am, methodType(String.class, int.class, String.class)). invokeExact(0, "foo"); }); @@ -1771,7 +1771,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class String x = (String) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class String x = (String) vh.getAndSet(0, 0, "foo"); }); checkWMTE(() -> { // index reference class @@ -1804,7 +1804,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class String x = (String) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class String x = (String) vh.getAndSetAcquire(0, 0, "foo"); }); checkWMTE(() -> { // index reference class @@ -1837,7 +1837,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class String x = (String) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class String x = (String) vh.getAndSetRelease(0, 0, "foo"); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java index 17cdcb7417f5..217c31a8a01c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodTypeValue.java @@ -480,7 +480,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // actual reference class Value x = (Value) vh.compareAndExchange(recv, Value.getInstance(10), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.compareAndExchange(0, Value.getInstance(10), Value.getInstance(10)); }); // Incorrect return type @@ -513,7 +513,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // actual reference class Value x = (Value) vh.compareAndExchangeAcquire(recv, Value.getInstance(10), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.compareAndExchangeAcquire(0, Value.getInstance(10), Value.getInstance(10)); }); // Incorrect return type @@ -546,7 +546,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // actual reference class Value x = (Value) vh.compareAndExchangeRelease(recv, Value.getInstance(10), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.compareAndExchangeRelease(0, Value.getInstance(10), Value.getInstance(10)); }); // Incorrect return type @@ -576,7 +576,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.getAndSet(0, Value.getInstance(10)); }); // Incorrect return type @@ -605,7 +605,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.getAndSetAcquire(0, Value.getInstance(10)); }); // Incorrect return type @@ -634,7 +634,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) vh.getAndSetRelease(0, Value.getInstance(10)); }); // Incorrect return type @@ -769,7 +769,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, Value x = (Value) hs.get(am, methodType(Value.class, VarHandleTestMethodTypeValue.class, Value.class, Class.class)). invokeExact(recv, Value.getInstance(10), Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) hs.get(am, methodType(Value.class, int.class , Value.class, Value.class)). invokeExact(0, Value.getInstance(10), Value.getInstance(10)); }); @@ -806,7 +806,7 @@ static void testInstanceFieldWrongMethodType(VarHandleTestMethodTypeValue recv, Value x = (Value) hs.get(am, methodType(Value.class, VarHandleTestMethodTypeValue.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class Value x = (Value) hs.get(am, methodType(Value.class, int.class, Value.class)). invokeExact(0, Value.getInstance(10)); }); @@ -1774,7 +1774,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class Value x = (Value) vh.getAndSet(0, 0, Value.getInstance(10)); }); checkWMTE(() -> { // index reference class @@ -1807,7 +1807,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class Value x = (Value) vh.getAndSetAcquire(0, 0, Value.getInstance(10)); }); checkWMTE(() -> { // index reference class @@ -1840,7 +1840,7 @@ static void testArrayWrongMethodType(VarHandle vh) throws Throwable { checkCCE(() -> { // value reference class Value x = (Value) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class Value x = (Value) vh.getAndSetRelease(0, 0, Value.getInstance(10)); }); checkWMTE(() -> { // index reference class diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template index 54357cc61f20..332f6ac8453d 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template @@ -32,8 +32,8 @@ #end[Value] * @run junit/othervm -Diters=10 -Xint VarHandleTestAccess$Type$ * - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestAccess$Type$ * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestAccess$Type$ @@ -394,7 +394,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { // Lazy { $type$ x = ($type$) vh.getAcquire(recv); - assertEquals($value1$, x, "getRelease $type$ value"); + assertEquals($value1$, x, "getAcquire $type$ value"); } // Opaque @@ -538,7 +538,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { // Lazy { $type$ x = ($type$) vh.getAcquire(); - assertEquals($value1$, x, "getRelease $type$ value"); + assertEquals($value1$, x, "getAcquire $type$ value"); } // Opaque @@ -880,7 +880,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(recv, $value1$); $type$ o = ($type$) vh.getAndAddRelease(recv, $value2$); - assertEquals($value1$, o, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) vh.get(recv); assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } @@ -1289,7 +1289,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set($value1$); $type$ o = ($type$) vh.getAndAddRelease($value2$); - assertEquals($value1$, o, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) vh.get(); assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } @@ -1701,7 +1701,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { vh.set(array, i, $value1$); $type$ o = ($type$) vh.getAndAddRelease(array, i, $value2$); - assertEquals($value1$, o, "getAndAddRelease$type$"); + assertEquals($value1$, o, "getAndAddRelease $type$"); $type$ x = ($type$) vh.get(array, i); assertEquals(($type$)($value1$ + $value2$), x, "getAndAddRelease $type$ value"); } @@ -2063,57 +2063,57 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); // CompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.compareAndSet(array, 0, $value1$, value); }); // WeakCompareAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, $value1$, value); }); // WeakCompareAndSetVolatile - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSet(array, 0, $value1$, value); }); // WeakCompareAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, $value1$, value); }); // WeakCompareAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, $value1$, value); }); // CompareAndExchange - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.compareAndExchange(array, 0, $value1$, value); }); // CompareAndExchangeAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.compareAndExchangeAcquire(array, 0, $value1$, value); }); // CompareAndExchangeRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.compareAndExchangeRelease(array, 0, $value1$, value); }); // GetAndSet - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkASE(() -> { // receiver reference class + checkASE(() -> { $type$ x = ($type$) vh.getAndSetRelease(array, 0, value); }); } @@ -2144,57 +2144,57 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet(recv, $value1$, value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain(recv, $value1$, value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet(recv, $value1$, value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease(recv, $value1$, value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchange(recv, $value1$, value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeAcquire(recv, $value1$, value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeRelease(recv, $value1$, value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSet(recv, value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetAcquire(recv, value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetRelease(recv, value); }); } @@ -2223,57 +2223,57 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet($value1$, value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain($value1$, value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet($value1$, value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire($value1$, value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease($value1$, value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchange($value1$, value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeAcquire($value1$, value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeRelease($value1$, value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSet(value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetAcquire(value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetRelease(value); }); } @@ -2303,57 +2303,57 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { }); // CompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.compareAndSet(array, 0, $value1$, value); }); // WeakCompareAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetPlain(array, 0, $value1$, value); }); // WeakCompareAndSetVolatile - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSet(array, 0, $value1$, value); }); // WeakCompareAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetAcquire(array, 0, $value1$, value); }); // WeakCompareAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { boolean r = vh.weakCompareAndSetRelease(array, 0, $value1$, value); }); // CompareAndExchange - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchange(array, 0, $value1$, value); }); // CompareAndExchangeAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeAcquire(array, 0, $value1$, value); }); // CompareAndExchangeRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.compareAndExchangeRelease(array, 0, $value1$, value); }); // GetAndSet - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSet(array, 0, value); }); // GetAndSetAcquire - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetAcquire(array, 0, value); }); // GetAndSetRelease - checkNPE(() -> { // receiver reference class + checkNPE(() -> { $type$ x = ($type$) vh.getAndSetRelease(array, 0, value); }); } diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template index 9a40bfb27806..f30a43390251 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ /* * @test * @bug 8154556 - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:TieredStopAtLevel=1 VarHandleTestByteArrayAs$Type$ * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestByteArrayAs$Type$ * @run junit/othervm/timeout=360 -Diters=2000 -XX:CompileThresholdScaling=0.1 -XX:-TieredCompilation VarHandleTestByteArrayAs$Type$ @@ -59,9 +59,9 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { public List setupVarHandleSources(boolean same) { // Combinations of VarHandle byte[] or ByteBuffer List vhss = new ArrayList<>(); - for (MemoryMode endianess : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { + for (MemoryMode endianness : List.of(MemoryMode.BIG_ENDIAN, MemoryMode.LITTLE_ENDIAN)) { - ByteOrder bo = endianess == MemoryMode.BIG_ENDIAN + ByteOrder bo = endianness == MemoryMode.BIG_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; Class arrayType; @@ -77,12 +77,12 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { } VarHandleSource aeh = new VarHandleSource( MethodHandles.byteArrayViewVarHandle(arrayType, bo), false, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(aeh); VarHandleSource bbh = new VarHandleSource( MethodHandles.byteBufferViewVarHandle(arrayType, bo), true, - endianess, MemoryMode.READ_WRITE); + endianness, MemoryMode.READ_WRITE); vhss.add(bbh); } return vhss; @@ -1627,7 +1627,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { // Lazy { $type$ x = ($type$) vh.getAcquire(array, i); - assertEquals(v, x, "getRelease $type$ value"); + assertEquals(v, x, "getAcquire $type$ value"); } // Opaque diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template index dff8b0306042..9d5dd44516b0 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template @@ -30,8 +30,8 @@ * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value #end[Value] - * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop sets to 2000 iterations - * to hit compilation thresholds + * @comment Set CompileThresholdScaling to 0.1 so that the warmup loop set to 2000 iterations + * hits compilation thresholds * @run junit/othervm -Diters=2000 -XX:CompileThresholdScaling=0.1 VarHandleTestMethodHandleAccess$Type$ */ @@ -320,11 +320,31 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { // Compare set and get { + hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value2$); assertEquals($value1$, o, "getAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); assertEquals($value2$, x, "getAndSet $type$ value"); } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); + + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_ACQUIRE).invokeExact(recv, $value2$); + assertEquals($value1$, o, "getAndSetAcquire $type$"); + $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals($value2$, x, "getAndSetAcquire $type$ value"); + } + + { + hs.get(TestAccessMode.SET).invokeExact(recv, $value1$); + + $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET_RELEASE).invokeExact(recv, $value2$); + assertEquals($value1$, o, "getAndSetRelease $type$"); + $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); + assertEquals($value2$, x, "getAndSetRelease $type$ value"); + } #end[CAS] #if[AtomicAdd] @@ -647,7 +667,7 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); - assertEquals($value1$, x, "failing weakCompareAndSetRe $type$ value"); + assertEquals($value1$, x, "failing weakCompareAndSet $type$ value"); } // Compare set and get @@ -660,7 +680,6 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { assertEquals($value2$, x, "getAndSet $type$ value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact($value1$); @@ -670,7 +689,6 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { assertEquals($value2$, x, "getAndSetAcquire $type$ value"); } - // Compare set and get { hs.get(TestAccessMode.SET).invokeExact($value1$); @@ -981,10 +999,10 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, $value1$, $value3$); - assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); + boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, $value1$, $value3$); + assertEquals(success, false, "failing weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); - assertEquals($value2$, x, "failing weakCompareAndSetAcquire $type$ value"); + assertEquals($value2$, x, "failing weakCompareAndSetRelease $type$ value"); } { diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template index f44b17b2d879..726b8ccb5c2e 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template @@ -488,7 +488,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // actual reference class $type$ x = ($type$) vh.compareAndExchange(recv, $value1$, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.compareAndExchange(0, $value1$, $value1$); }); // Incorrect return type @@ -521,7 +521,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // actual reference class $type$ x = ($type$) vh.compareAndExchangeAcquire(recv, $value1$, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.compareAndExchangeAcquire(0, $value1$, $value1$); }); // Incorrect return type @@ -554,7 +554,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // actual reference class $type$ x = ($type$) vh.compareAndExchangeRelease(recv, $value1$, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.compareAndExchangeRelease(0, $value1$, $value1$); }); // Incorrect return type @@ -584,7 +584,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSet(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndSet(0, $value1$); }); // Incorrect return type @@ -613,7 +613,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSetAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndSetAcquire(0, $value1$); }); // Incorrect return type @@ -642,7 +642,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSetRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndSetRelease(0, $value1$); }); // Incorrect return type @@ -673,7 +673,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndAdd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndAdd(0, $value1$); }); // Incorrect return type @@ -702,7 +702,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndAddAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndAddAcquire(0, $value1$); }); // Incorrect return type @@ -731,7 +731,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndAddRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndAddRelease(0, $value1$); }); // Incorrect return type @@ -762,7 +762,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseOr(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseOr(0, $value1$); }); // Incorrect return type @@ -792,7 +792,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseOrAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseOrAcquire(0, $value1$); }); // Incorrect return type @@ -817,27 +817,27 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) vh.getAndBitwiseOrRelease(null, $value1$); }); checkCCE(() -> { // receiver reference class - $type$ x = ($type$) vh.getAndBitwiseOr(Void.class, $value1$); + $type$ x = ($type$) vh.getAndBitwiseOrRelease(Void.class, $value1$); }); check{#if[Object]?CCE:WMTE}(() -> { // value reference class - $type$ x = ($type$) vh.getAndBitwiseOr(recv, Void.class); + $type$ x = ($type$) vh.getAndBitwiseOrRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - $type$ x = ($type$) vh.getAndBitwiseOr(0, $value1$); + checkWMTE(() -> { // receiver primitive class + $type$ x = ($type$) vh.getAndBitwiseOrRelease(0, $value1$); }); // Incorrect return type check{#if[Object]?CCE:WMTE}(() -> { // reference class - Void r = (Void) vh.getAndBitwiseOr(recv, $value1$); + Void r = (Void) vh.getAndBitwiseOrRelease(recv, $value1$); }); checkWMTE(() -> { // primitive class - $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseOr(recv, $value1$); + $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseOrRelease(recv, $value1$); }); // Incorrect arity checkWMTE(() -> { // 0 - $type$ x = ($type$) vh.getAndBitwiseOr(); + $type$ x = ($type$) vh.getAndBitwiseOrRelease(); }); checkWMTE(() -> { // > - $type$ x = ($type$) vh.getAndBitwiseOr(recv, $value1$, Void.class); + $type$ x = ($type$) vh.getAndBitwiseOrRelease(recv, $value1$, Void.class); }); @@ -852,7 +852,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseAnd(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseAnd(0, $value1$); }); // Incorrect return type @@ -882,7 +882,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseAndAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseAndAcquire(0, $value1$); }); // Incorrect return type @@ -907,27 +907,27 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) vh.getAndBitwiseAndRelease(null, $value1$); }); checkCCE(() -> { // receiver reference class - $type$ x = ($type$) vh.getAndBitwiseAnd(Void.class, $value1$); + $type$ x = ($type$) vh.getAndBitwiseAndRelease(Void.class, $value1$); }); check{#if[Object]?CCE:WMTE}(() -> { // value reference class - $type$ x = ($type$) vh.getAndBitwiseAnd(recv, Void.class); + $type$ x = ($type$) vh.getAndBitwiseAndRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - $type$ x = ($type$) vh.getAndBitwiseAnd(0, $value1$); + checkWMTE(() -> { // receiver primitive class + $type$ x = ($type$) vh.getAndBitwiseAndRelease(0, $value1$); }); // Incorrect return type check{#if[Object]?CCE:WMTE}(() -> { // reference class - Void r = (Void) vh.getAndBitwiseAnd(recv, $value1$); + Void r = (Void) vh.getAndBitwiseAndRelease(recv, $value1$); }); checkWMTE(() -> { // primitive class - $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseAnd(recv, $value1$); + $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseAndRelease(recv, $value1$); }); // Incorrect arity checkWMTE(() -> { // 0 - $type$ x = ($type$) vh.getAndBitwiseAnd(); + $type$ x = ($type$) vh.getAndBitwiseAndRelease(); }); checkWMTE(() -> { // > - $type$ x = ($type$) vh.getAndBitwiseAnd(recv, $value1$, Void.class); + $type$ x = ($type$) vh.getAndBitwiseAndRelease(recv, $value1$, Void.class); }); @@ -942,7 +942,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseXor(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseXor(0, $value1$); }); // Incorrect return type @@ -972,7 +972,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseXorAcquire(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) vh.getAndBitwiseXorAcquire(0, $value1$); }); // Incorrect return type @@ -997,27 +997,27 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) vh.getAndBitwiseXorRelease(null, $value1$); }); checkCCE(() -> { // receiver reference class - $type$ x = ($type$) vh.getAndBitwiseXor(Void.class, $value1$); + $type$ x = ($type$) vh.getAndBitwiseXorRelease(Void.class, $value1$); }); check{#if[Object]?CCE:WMTE}(() -> { // value reference class - $type$ x = ($type$) vh.getAndBitwiseXor(recv, Void.class); + $type$ x = ($type$) vh.getAndBitwiseXorRelease(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class - $type$ x = ($type$) vh.getAndBitwiseXor(0, $value1$); + checkWMTE(() -> { // receiver primitive class + $type$ x = ($type$) vh.getAndBitwiseXorRelease(0, $value1$); }); // Incorrect return type check{#if[Object]?CCE:WMTE}(() -> { // reference class - Void r = (Void) vh.getAndBitwiseXor(recv, $value1$); + Void r = (Void) vh.getAndBitwiseXorRelease(recv, $value1$); }); checkWMTE(() -> { // primitive class - $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseXor(recv, $value1$); + $wrong_primitive_type$ x = ($wrong_primitive_type$) vh.getAndBitwiseXorRelease(recv, $value1$); }); // Incorrect arity checkWMTE(() -> { // 0 - $type$ x = ($type$) vh.getAndBitwiseXor(); + $type$ x = ($type$) vh.getAndBitwiseXorRelease(); }); checkWMTE(() -> { // > - $type$ x = ($type$) vh.getAndBitwiseXor(recv, $value1$, Void.class); + $type$ x = ($type$) vh.getAndBitwiseXorRelease(recv, $value1$, Void.class); }); #end[Bitwise] } @@ -1137,7 +1137,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) hs.get(am, methodType($type$.class, VarHandleTestMethodType$Type$.class, $type$.class, Class.class)). invokeExact(recv, $value1$, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) hs.get(am, methodType($type$.class, int.class , $type$.class, $type$.class)). invokeExact(0, $value1$, $value1$); }); @@ -1174,7 +1174,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) hs.get(am, methodType($type$.class, VarHandleTestMethodType$Type$.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) hs.get(am, methodType($type$.class, int.class, $type$.class)). invokeExact(0, $value1$); }); @@ -1213,7 +1213,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) hs.get(am, methodType($type$.class, VarHandleTestMethodType$Type$.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) hs.get(am, methodType($type$.class, int.class, $type$.class)). invokeExact(0, $value1$); }); @@ -1252,7 +1252,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { $type$ x = ($type$) hs.get(am, methodType($type$.class, VarHandleTestMethodType$Type$.class, Class.class)). invokeExact(recv, Void.class); }); - checkWMTE(() -> { // reciever primitive class + checkWMTE(() -> { // receiver primitive class $type$ x = ($type$) hs.get(am, methodType($type$.class, int.class, $type$.class)). invokeExact(0, $value1$); }); @@ -1717,7 +1717,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); - // GetAndBitwiseOrReleaseRelease + // GetAndBitwiseOrRelease // Incorrect argument types check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseOrRelease(Void.class); @@ -1780,7 +1780,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); - // GetAndBitwiseAndReleaseRelease + // GetAndBitwiseAndRelease // Incorrect argument types check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseAndRelease(Void.class); @@ -1843,7 +1843,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { }); - // GetAndBitwiseXorReleaseRelease + // GetAndBitwiseXorRelease // Incorrect argument types check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndBitwiseXorRelease(Void.class); @@ -2530,7 +2530,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSet(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class $type$ x = ($type$) vh.getAndSet(0, 0, $value1$); }); checkWMTE(() -> { // index reference class @@ -2563,7 +2563,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSetAcquire(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class $type$ x = ($type$) vh.getAndSetAcquire(0, 0, $value1$); }); checkWMTE(() -> { // index reference class @@ -2596,7 +2596,7 @@ public class VarHandleTestMethodType$Type$ extends VarHandleBaseTest { check{#if[Object]?CCE:WMTE}(() -> { // value reference class $type$ x = ($type$) vh.getAndSetRelease(array, 0, Void.class); }); - checkWMTE(() -> { // reciarrayever primitive class + checkWMTE(() -> { // array primitive class $type$ x = ($type$) vh.getAndSetRelease(0, 0, $value1$); }); checkWMTE(() -> { // index reference class From b1f975efa481bd5e20c1b7d58a87d0866df205e6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 3 Sep 2026 03:45:27 +0000 Subject: [PATCH 222/223] 8391716: ProblemList gc/metaspace/TestMetaspaceFirstGC.java Reviewed-by: azvegint --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 74759f8bf2eb..2eca4b5cddd2 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -87,6 +87,7 @@ gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#generational 83869 gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#default 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#generational 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#default 8386964 generic-all +gc/metaspace/TestMetaspaceFirstGC.java 8391711 generic-all ############################################################################# From 032c0a1f34825129f2b9be9a1ed2e81c9c8402d0 Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Fri, 4 Sep 2026 19:48:00 +0200 Subject: [PATCH 223/223] New test ExitOnFullCodeCacheTest doesn't work with large pages (including THP). --- .../jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java b/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java index c8074bd05ca9..d69384e8de02 100644 --- a/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java +++ b/test/hotspot/jtreg/compiler/codecache/ExitOnFullCodeCacheTest.java @@ -71,6 +71,8 @@ public static void main(String[] args) throws Exception { "-XX:+ExitOnFullCodeCache", "-XX:NonNMethodCodeHeapSize=" + NON_NMETHOD_KB + "K", "-XX:ReservedCodeCacheSize=" + reservedKB + "K", + // SapMachine 2025-12-10 We don't get exact matches when rounding to large page sizes. + "-XX:-UseLargePages", "-version"); // The invariant that must always hold, on every platform, is that the