From ecc77a5b4a84c84ffa1580174872af6df3a4f6ca Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 9 Oct 2024 14:57:37 +0000 Subject: [PATCH 01/24] 8336702: C2 compilation fails with "all memory state should have been processed" assert Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/loopnode.cpp | 14 ++++- .../TestSafePointWithEAState.java | 63 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 5e00270402ea1..6cb50b3dee2b5 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -692,14 +692,24 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal // We can only use that safepoint if there's no side effect between the backedge and the safepoint. - // mm is used for book keeping + // mm is the memory state at the safepoint (when it's a MergeMem) + // no_side_effect_since_safepoint() goes over the memory state at the backedge. It resets the mm input for each + // component of the memory state it encounters so it points to the base memory. Once no_side_effect_since_safepoint() + // is done, if no side effect after the safepoint was found, mm should transform to the base memory: the states at + // the backedge and safepoint are the same so all components of the memory state at the safepoint should have been + // reset. MergeMemNode* mm = nullptr; #ifdef ASSERT if (mem->is_MergeMem()) { mm = mem->clone()->as_MergeMem(); _igvn._worklist.push(mm); for (MergeMemStream mms(mem->as_MergeMem()); mms.next_non_empty(); ) { - if (mms.alias_idx() != Compile::AliasIdxBot && loop != get_loop(ctrl_or_self(mms.memory()))) { + // Loop invariant memory state won't be reset by no_side_effect_since_safepoint(). Do it here. + // Escape Analysis can add state to mm that it doesn't add to the backedge memory Phis, breaking verification + // code that relies on mm. Clear that extra state here. + if (mms.alias_idx() != Compile::AliasIdxBot && + (loop != get_loop(ctrl_or_self(mms.memory())) || + (mms.adr_type()->isa_oop_ptr() && mms.adr_type()->is_known_instance()))) { mm->set_memory_at(mms.alias_idx(), mem->as_MergeMem()->base_memory()); } } diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java new file mode 100644 index 0000000000000..a04af09570fb9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8336702 + * @summary C2 compilation fails with "all memory state should have been processed" assert + * + * @run main/othervm TestSafePointWithEAState + * + */ + +public class TestSafePointWithEAState { + int[] b = new int[400]; + + void c() { + int e; + float f; + for (long d = 0; d < 5000; d++) { + e = 1; + while ((e += 3) < 200) { + if (d < b.length) { + for (int g = 0; g < 10000; ++g) ; + } + } + synchronized (TestSafePointWithEAState.class) { + f = new h(e).n; + } + } + } + + public static void main(String[] m) { + TestSafePointWithEAState o = new TestSafePointWithEAState(); + o.c(); + } +} + +class h { + float n; + h(float n) { + this.n = n; + } +} From ff2f39f24018436556a8956ec55da433dc697437 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 9 Oct 2024 14:59:15 +0000 Subject: [PATCH 02/24] 8340214: C2 compilation asserts with "no node with a side effect" in PhaseIdealLoop::try_sink_out_of_loop Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/compile.cpp | 18 ++-- src/hotspot/share/opto/graphKit.cpp | 2 + src/hotspot/share/opto/library_call.cpp | 14 +-- .../types/TestBadMemSliceWithInterfaces.java | 101 ++++++++++++++++++ 4 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index dc91d6db1e398..fa0d39057cb12 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1466,12 +1466,18 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { } else { ciInstanceKlass *canonical_holder = ik->get_canonical_holder(offset); assert(offset < canonical_holder->layout_helper_size_in_bytes(), ""); - if (!ik->equals(canonical_holder) || tj->offset() != offset) { - if( is_known_inst ) { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, nullptr, offset, to->instance_id()); - } else { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, nullptr, offset); - } + assert(tj->offset() == offset, "no change to offset expected"); + bool xk = to->klass_is_exact(); + int instance_id = to->instance_id(); + + // If the input type's class is the holder: if exact, the type only includes interfaces implemented by the holder + // but if not exact, it may include extra interfaces: build new type from the holder class to make sure only + // its interfaces are included. + if (xk && ik->equals(canonical_holder)) { + assert(tj == TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id), "exact type should be canonical type"); + } else { + assert(xk || !is_known_inst, "Known instance should be exact type"); + tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id); } } } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 19605dda16c03..27120c5ea1e73 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1558,6 +1558,7 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, bool mismatched, bool unsafe, uint8_t barrier_data) { + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = nullptr; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1587,6 +1588,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, bool unsafe, int barrier_data) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); const TypePtr* adr_type = nullptr; debug_only(adr_type = C->get_adr_type(adr_idx)); Node *mem = memory(adr_idx); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 386dd41f2e956..4ab4eea6f8f68 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2959,11 +2959,10 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch Node* thread = ideal.thread(); Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); - const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); sync_kit(ideal); - access_store_at(nullptr, jt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); ideal.sync_kit(this); } ideal.end_if(); @@ -3325,7 +3324,9 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the threadObj. Node* threadObj_epoch_offset = basic_plus_adr(threadObj, java_lang_Thread::jfr_epoch_offset()); - Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, + _gvn.type(threadObj_epoch_offset)->isa_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3344,7 +3345,8 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the vthread. Node* vthread_epoch_offset = basic_plus_adr(vthread, java_lang_Thread::jfr_epoch_offset()); - Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, _gvn.type(vthread_epoch_offset)->is_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3590,7 +3592,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) { // Load the raw epoch value from the vthread. Node* epoch_offset = basic_plus_adr(thread, java_lang_Thread::jfr_epoch_offset()); - Node* epoch_raw = access_load_at(thread, epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* epoch_raw = access_load_at(thread, epoch_offset, _gvn.type(epoch_offset)->is_ptr(), TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. diff --git a/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java new file mode 100644 index 0000000000000..5090c2dd6cf97 --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8340214 + * @summary C2 compilation asserts with "no node with a side effect" in PhaseIdealLoop::try_sink_out_of_loop + * + * @run main/othervm -XX:-BackgroundCompilation TestBadMemSliceWithInterfaces + * + */ + +public class TestBadMemSliceWithInterfaces { + public static void main(String[] args) { + B b = new B(); + C c = new C(); + for (int i = 0; i < 20_000; i++) { + test1(b, c, true); + test1(b, c, false); + b.field = 0; + c.field = 0; + int res = test2(b, c, true); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + res = test2(b, c, false); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + } + } + + private static void test1(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + for (int i = 0; i < 1000; i++) { + a.field = 42; + } + } + + private static int test2(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + int v = 0; + for (int i = 0; i < 2; i++) { + v += a.field; + a.field = 42; + } + return v; + } + + interface I { + void m(); + } + + static class A { + int field; + } + + static class B extends A implements I { + @Override + public void m() { + + } + } + + static class C extends A implements I { + @Override + public void m() { + + } + } +} From c30ad0124e7743f3a4c29ef901761f8fcc53de10 Mon Sep 17 00:00:00 2001 From: Kangcheng Xu Date: Wed, 9 Oct 2024 15:07:13 +0000 Subject: [PATCH 03/24] 8325495: C2: implement optimization for series of Add of unique value Reviewed-by: chagedorn, roland --- src/hotspot/share/opto/addnode.cpp | 150 ++++++++++ src/hotspot/share/opto/addnode.hpp | 7 + .../compiler/c2/TestSerialAdditions.java | 257 ++++++++++++++++++ 3 files changed, 414 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 9a7d93dc469ba..802af20adae12 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -395,9 +395,159 @@ Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) { } } + // Convert a + a + ... + a into a*n + Node* serial_additions = convert_serial_additions(phase, bt); + if (serial_additions != nullptr) { + return serial_additions; + } + return AddNode::Ideal(phase, can_reshape); } +// Try to convert a serial of additions into a single multiplication. Also convert `(a * CON) + a` to `(CON + 1) * a` as +// a side effect. On success, a new MulNode is returned. +Node* AddNode::convert_serial_additions(PhaseGVN* phase, BasicType bt) { + // We need to make sure that the current AddNode is not part of a MulNode that has already been optimized to a + // power-of-2 addition (e.g., 3 * a => (a << 2) + a). Without this check, GVN would keep trying to optimize the same + // node and can't progress. For example, 3 * a => (a << 2) + a => 3 * a => (a << 2) + a => ... + if (find_power_of_two_addition_pattern(this, bt, nullptr) != nullptr) { + return nullptr; + } + + Node* in1 = in(1); + Node* in2 = in(2); + jlong multiplier; + + // While multiplications can be potentially optimized to power-of-2 subtractions (e.g., a * 7 => (a << 3) - a), + // (x - y) + y => x is already handled by the Identity() methods. So, we don't need to check for that pattern here. + if (find_simple_addition_pattern(in1, bt, &multiplier) == in2 + || find_simple_lshift_pattern(in1, bt, &multiplier) == in2 + || find_simple_multiplication_pattern(in1, bt, &multiplier) == in2 + || find_power_of_two_addition_pattern(in1, bt, &multiplier) == in2) { + multiplier++; // +1 for the in2 term + + Node* con = (bt == T_INT) + ? (Node*) phase->intcon((jint) multiplier) // intentional type narrowing to allow overflow at max_jint + : (Node*) phase->longcon(multiplier); + return MulNode::make(con, in2, bt); + } + + return nullptr; +} + +// Try to match `a + a`. On success, return `a` and set `2` as `multiplier`. +// The method matches `n` for pattern: AddNode(a, a). +Node* AddNode::find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier) { + if (n->Opcode() == Op_Add(bt) && n->in(1) == n->in(2)) { + *multiplier = 2; + return n->in(1); + } + + return nullptr; +} + +// Try to match `a << CON`. On success, return `a` and set `1 << CON` as `multiplier`. +// Match `n` for pattern: LShiftNode(a, CON). +// Note that the power-of-2 multiplication optimization could potentially convert a MulNode to this pattern. +Node* AddNode::find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier) { + // Note that power-of-2 multiplication optimization could potentially convert a MulNode to this pattern + if (n->Opcode() == Op_LShift(bt) && n->in(2)->is_Con()) { + Node* con = n->in(2); + if (con->is_top()) { + return nullptr; + } + + *multiplier = ((jlong) 1 << con->get_int()); + return n->in(1); + } + + return nullptr; +} + +// Try to match `CON * a`. On success, return `a` and set `CON` as `multiplier`. +// Match `n` for patterns: +// - MulNode(CON, a) +// - MulNode(a, CON) +Node* AddNode::find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier) { + // This optimization technically only produces MulNode(CON, a), but we might as match MulNode(a, CON), too. + if (n->Opcode() == Op_Mul(bt) && (n->in(1)->is_Con() || n->in(2)->is_Con())) { + Node* con = n->in(1); + Node* base = n->in(2); + + // swap ConNode to lhs for easier matching + if (!con->is_Con()) { + swap(con, base); + } + + if (con->is_top()) { + return nullptr; + } + + *multiplier = con->get_integer_as_long(bt); + return base; + } + + return nullptr; +} + +// Try to match `(a << CON1) + (a << CON2)`. On success, return `a` and set `(1 << CON1) + (1 << CON2)` as `multiplier`. +// Match `n` for patterns: +// - AddNode(LShiftNode(a, CON), LShiftNode(a, CON)/a) +// - AddNode(LShiftNode(a, CON)/a, LShiftNode(a, CON)) +// given that lhs is different from rhs. +// Note that one of the term of the addition could simply be `a` (i.e., a << 0). Calling this function with `multiplier` +// being null is safe. +Node* AddNode::find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier) { + if (n->Opcode() == Op_Add(bt) && n->in(1) != n->in(2)) { + Node* lhs = n->in(1); + Node* rhs = n->in(2); + + // swap LShiftNode to lhs for easier matching + if (lhs->Opcode() != Op_LShift(bt)) { + swap(lhs, rhs); + } + + // AddNode(LShiftNode(a, CON), *)? + if (lhs->Opcode() != Op_LShift(bt) || !lhs->in(2)->is_Con()) { + return nullptr; + } + + jlong lhs_multiplier = 0; + if (multiplier != nullptr) { + Node* con = lhs->in(2); + if (con->is_top()) { + return nullptr; + } + + lhs_multiplier = (jlong) 1 << con->get_int(); + } + + // AddNode(LShiftNode(a, CON), a)? + if (lhs->in(1) == rhs) { + if (multiplier != nullptr) { + *multiplier = lhs_multiplier + 1; + } + + return rhs; + } + + // AddNode(LShiftNode(a, CON), LShiftNode(a, CON2))? + if (rhs->Opcode() == Op_LShift(bt) && lhs->in(1) == rhs->in(1) && rhs->in(2)->is_Con()) { + if (multiplier != nullptr) { + Node* con = rhs->in(2); + if (con->is_top()) { + return nullptr; + } + + *multiplier = lhs_multiplier + ((jlong) 1 << con->get_int()); + } + + return lhs->in(1); + } + return nullptr; + } + return nullptr; +} Node* AddINode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* in1 = in(1); diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 8879606954a52..8afbb440572bf 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -42,6 +42,13 @@ typedef const Pair ConstAddOperands; // by virtual functions. class AddNode : public Node { virtual uint hash() const; + + Node* convert_serial_additions(PhaseGVN* phase, BasicType bt); + static Node* find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier); + static Node* find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier); + public: AddNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Add); diff --git a/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java new file mode 100644 index 0000000000000..c52f17dd9757b --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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; + +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +import java.util.Random; + +/* + * @test + * @bug 8325495 + * @summary C2 should optimize for series of Add of unique value. e.g., a + a + ... + a => a*n + * @library /test/lib / + * @run driver compiler.c2.TestSerialAdditions + */ +public class TestSerialAdditions { + private static final Random RNG = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { + "addTo2", + "addTo3", + "addTo4", + "shiftAndAddTo4", + "mulAndAddTo4", + "addTo5", + "addTo6", + "addTo7", + "addTo8", + "addTo16", + "addAndShiftTo16", + "addTo42", + "mulAndAddTo42", + "mulAndAddToMax", + "mulAndAddToOverflow", + "mulAndAddToZero", + "mulAndAddToMinus1", + "mulAndAddToMinus42" + }) + private void runIntTests() { + for (int a : new int[] { 0, 1, Integer.MIN_VALUE, Integer.MAX_VALUE, RNG.nextInt() }) { + Asserts.assertEQ(a * 2, addTo2(a)); + Asserts.assertEQ(a * 3, addTo3(a)); + Asserts.assertEQ(a * 4, addTo4(a)); + Asserts.assertEQ(a * 4, shiftAndAddTo4(a)); + Asserts.assertEQ(a * 4, mulAndAddTo4(a)); + Asserts.assertEQ(a * 5, addTo5(a)); + Asserts.assertEQ(a * 6, addTo6(a)); + Asserts.assertEQ(a * 7, addTo7(a)); + Asserts.assertEQ(a * 8, addTo8(a)); + Asserts.assertEQ(a * 16, addTo16(a)); + Asserts.assertEQ(a * 16, addAndShiftTo16(a)); + Asserts.assertEQ(a * 42, addTo42(a)); + Asserts.assertEQ(a * 42, mulAndAddTo42(a)); + Asserts.assertEQ(a * Integer.MAX_VALUE, mulAndAddToMax(a)); + Asserts.assertEQ(a * Integer.MIN_VALUE, mulAndAddToOverflow(a)); + Asserts.assertEQ(0, mulAndAddToZero(a)); + Asserts.assertEQ(a * -1, mulAndAddToMinus1(a)); + Asserts.assertEQ(a * -42, mulAndAddToMinus42(a)); + } + } + + @Run(test = { + "mulAndAddToIntOverflowL", + "mulAndAddToMaxL", + "mulAndAddToOverflowL" + }) + private void runLongTests() { + for (long a : new long[] { 0, 1, Long.MIN_VALUE, Long.MAX_VALUE, RNG.nextLong() }) { + Asserts.assertEQ(a * (Integer.MAX_VALUE + 1L), mulAndAddToIntOverflowL(a)); + Asserts.assertEQ(a * Long.MAX_VALUE, mulAndAddToMaxL(a)); + Asserts.assertEQ(a * Long.MIN_VALUE, mulAndAddToOverflowL(a)); + } + } + + // ----- integer tests ----- + @Test + @IR(counts = { IRNode.ADD_I, "1" }) + @IR(failOn = IRNode.LSHIFT_I) + private static int addTo2(int a) { + return a + a; // Simple additions like a + a should be kept as-is + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" }) + private static int addTo3(int a) { + return a + a + a; // a*3 => (a<<1) + a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo4(int a) { + return a + a + a + a; // a*4 => a<<2 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int shiftAndAddTo4(int a) { + return (a << 1) + a + a; // a*2 + a + a => a*3 + a => a*4 => a<<2 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int mulAndAddTo4(int a) { + return a * 3 + a; // a*4 => a<<2 + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" }) + private static int addTo5(int a) { + return a + a + a + a + a; // a*5 => (a<<2) + a + } + + @Test + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "2" }) + private static int addTo6(int a) { + return a + a + a + a + a + a; // a*6 => (a<<1) + (a<<2) + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int addTo7(int a) { + return a + a + a + a + a + a + a; // a*7 => (a<<3) - a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo8(int a) { + return a + a + a + a + a + a + a + a; // a*8 => a<<3 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addTo16(int a) { + return a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a; // a*16 => a<<4 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int addAndShiftTo16(int a) { + return (a + a) << 3; // a<<(3 + 1) => a<<4 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int addTo42(int a) { + return a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a + a + a + a + a + a + a + a + a + + a + a; // a*42 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int mulAndAddTo42(int a) { + return a * 40 + a + a; // a*41 + a => a*42 + } + + private static final int INT_MAX_MINUS_ONE = Integer.MAX_VALUE - 1; + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int mulAndAddToMax(int a) { + return a * INT_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - a => (a<<31) - a + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1" }) + private static int mulAndAddToOverflow(int a) { + return a * Integer.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<31 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.CON_I, "1" }) + private static int mulAndAddToZero(int a) { + return a * -1 + a; // 0 + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" }) + private static int mulAndAddToMinus1(int a) { + return a * -2 + a; // a*-1 => a - (a<<1) + } + + @Test + @IR(failOn = IRNode.ADD_I) + @IR(counts = { IRNode.MUL_I, "1" }) + private static int mulAndAddToMinus42(int a) { + return a * -43 + a; // a*-42 + } + + // --- long tests --- + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1" }) + private static long mulAndAddToIntOverflowL(long a) { + return a * Integer.MAX_VALUE + a; // a*(INT_MAX+1) + } + + private static final long LONG_MAX_MINUS_ONE = Long.MAX_VALUE - 1; + + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1", IRNode.SUB_L, "1" }) + private static long mulAndAddToMaxL(long a) { + return a * LONG_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - 1 => (a<<63) - 1 + } + + @Test + @IR(failOn = IRNode.ADD_L) + @IR(counts = { IRNode.LSHIFT_L, "1" }) + private static long mulAndAddToOverflowL(long a) { + return a * Long.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<63 + } +} From e704c055a4cf2aab77cc2b3d034f5a8b8d9e3331 Mon Sep 17 00:00:00 2001 From: Oli Gillespie Date: Wed, 9 Oct 2024 15:28:44 +0000 Subject: [PATCH 04/24] 8340547: Starting many threads can delay safepoints Reviewed-by: shade, qamai, dholmes --- src/hotspot/share/prims/jvm.cpp | 3 ++- src/hotspot/share/runtime/globals.hpp | 4 ++++ src/hotspot/share/runtime/mutexLocker.cpp | 3 +++ src/hotspot/share/runtime/mutexLocker.hpp | 2 ++ src/hotspot/share/runtime/threads.cpp | 6 ++++-- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index a246c2c50d674..5d5d8aa7df9fa 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2948,9 +2948,10 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) // We must release the Threads_lock before we can post a jvmti event // in Thread::start. { + ConditionalMutexLocker throttle_ml(ThreadsLockThrottle_lock, UseThreadsLockThrottleLock); // Ensure that the C++ Thread and OSThread structures aren't freed before // we operate. - MutexLocker mu(Threads_lock); + MutexLocker ml(Threads_lock); // Since JDK 5 the java.lang.Thread threadStatus is used to prevent // re-starting an already started thread, so we should usually find diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 2bcc26043cd96..b568e76930476 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1991,6 +1991,10 @@ const int ObjectAlignmentInBytes = 8; \ product(bool, StressSecondarySupers, false, DIAGNOSTIC, \ "Use a terrible hash function in order to generate many collisions.") \ + \ + product(bool, UseThreadsLockThrottleLock, true, DIAGNOSTIC, \ + "Use an extra lock during Thread start and exit to alleviate" \ + "contention on Threads_lock.") \ // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index a0ba783c36408..769c7695192a8 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -66,6 +66,7 @@ Monitor* CodeCache_lock = nullptr; Mutex* TouchedMethodLog_lock = nullptr; Mutex* RetData_lock = nullptr; Monitor* VMOperation_lock = nullptr; +Monitor* ThreadsLockThrottle_lock = nullptr; Monitor* Threads_lock = nullptr; Mutex* NonJavaThreadsList_lock = nullptr; Mutex* NonJavaThreadsListSync_lock = nullptr; @@ -317,6 +318,8 @@ void mutex_init() { MUTEX_DEFN(JVMCIRuntime_lock , PaddedMonitor, safepoint, true); #endif + MUTEX_DEFN(ThreadsLockThrottle_lock , PaddedMonitor, safepoint); + // These locks have relative rankings, and inherit safepoint checking attributes from that rank. MUTEX_DEFL(VtableStubs_lock , PaddedMutex , CompiledIC_lock); // Also holds DumpTimeTable_lock MUTEX_DEFL(CodeCache_lock , PaddedMonitor, VtableStubs_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 3da859585019b..98cb27d0b812d 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -61,6 +61,8 @@ extern Monitor* CodeCache_lock; // a lock on the CodeCache extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info extern Mutex* RetData_lock; // a lock on installation of RetData inside method data extern Monitor* VMOperation_lock; // a lock on queue of vm_operations waiting to execute +extern Monitor* ThreadsLockThrottle_lock; // used by Thread start/exit to reduce competition for Threads_lock, + // so a VM thread calling a safepoint is prioritized extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads // (also used by Safepoints too to block threads creation/destruction) extern Mutex* NonJavaThreadsList_lock; // a lock on the NonJavaThreads list diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 8266bd86a9682..45aaa769856af 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1028,7 +1028,9 @@ void Threads::add(JavaThread* p, bool force_daemon) { void Threads::remove(JavaThread* p, bool is_daemon) { // Extra scope needed for Thread_lock, so we can check // that we do not remove thread without safepoint code notice - { MonitorLocker ml(Threads_lock); + { + ConditionalMutexLocker throttle_ml(ThreadsLockThrottle_lock, UseThreadsLockThrottleLock); + MonitorLocker ml(Threads_lock); if (ThreadIdTable::is_initialized()) { // This cleanup must be done before the current thread's GC barrier @@ -1076,7 +1078,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) { // Notify threads waiting in EscapeBarriers EscapeBarrier::thread_removed(p); - } // unlock Threads_lock + } // unlock Threads_lock and ThreadsLockThrottle_lock // Reduce the ObjectMonitor ceiling for the exiting thread. ObjectSynchronizer::dec_in_use_list_ceiling(); From 950e3a7587ed3269aab0c3b6625b9cc9149d34d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 9 Oct 2024 15:56:38 +0000 Subject: [PATCH 05/24] 8341625: Improve ZipFile validation of the END header Reviewed-by: lancea --- .../share/classes/java/util/zip/ZipFile.java | 9 +- .../util/zip/ZipFile/EndOfCenValidation.java | 160 ++++++++++++++++-- 2 files changed, 152 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 00d100b21a874..21b9593c0172a 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1605,7 +1605,7 @@ private final int readAt(byte[] buf, int off, int len, long pos) private static class End { - int centot; // 4 bytes + long centot; // 4 bytes long cenlen; // 4 bytes long cenoff; // 4 bytes long endpos; // 4 bytes @@ -1697,7 +1697,7 @@ private End findEND() throws IOException { // to use the end64 values end.cenlen = cenlen64; end.cenoff = cenoff64; - end.centot = (int)centot64; // assume total < 2g + end.centot = centot64; end.endpos = end64pos; } catch (IOException x) {} // no ZIP64 loc/end return end; @@ -1733,11 +1733,14 @@ private void initCEN(int knownTotal) throws IOException { if (end.cenlen > MAX_CEN_SIZE) { zerror("invalid END header (central directory size too large)"); } + if (end.centot < 0 || end.centot > end.cenlen / CENHDR) { + zerror("invalid END header (total entries count too large)"); + } cen = this.cen = new byte[(int)end.cenlen]; if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen) { zerror("read CEN tables failed"); } - this.total = end.centot; + this.total = Math.toIntExact(end.centot); } else { cen = this.cen; this.total = knownTotal; diff --git a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java index ec6542768c58f..7adcfb9c12845 100644 --- a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java +++ b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java @@ -25,13 +25,15 @@ * @bug 8272746 * @modules java.base/jdk.internal.util * @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit - * @run testng/othervm EndOfCenValidation + * @run junit/othervm EndOfCenValidation */ import jdk.internal.util.ArraysSupport; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.io.*; import java.nio.ByteBuffer; @@ -43,12 +45,13 @@ import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.EnumSet; +import java.util.HexFormat; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; /** * This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where @@ -70,7 +73,7 @@ public class EndOfCenValidation { private static final int ENDSIZ = ZipFile.ENDSIZ; // Offset of CEN size field within ENDHDR private static final int ENDOFF = ZipFile.ENDOFF; // Offset of CEN offset field within ENDHDR // Maximum allowed CEN size allowed by ZipFile - private static int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + private static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; // Expected message when CEN size does not match file size private static final String INVALID_CEN_BAD_SIZE = "invalid END header (bad central directory size)"; @@ -78,6 +81,8 @@ public class EndOfCenValidation { private static final String INVALID_CEN_BAD_OFFSET = "invalid END header (bad central directory offset)"; // Expected message when CEN size is too large private static final String INVALID_CEN_SIZE_TOO_LARGE = "invalid END header (central directory size too large)"; + // Expected message when total entry count is too large + private static final String INVALID_BAD_ENTRY_COUNT = "invalid END header (total entries count too large)"; // A valid ZIP file, used as a template private byte[] zipBytes; @@ -86,7 +91,7 @@ public class EndOfCenValidation { * Create a valid ZIP file, used as a template * @throws IOException if an error occurs */ - @BeforeTest + @BeforeEach public void setup() throws IOException { zipBytes = templateZip(); } @@ -95,7 +100,7 @@ public void setup() throws IOException { * Delete big files after test, in case the file system did not support sparse files. * @throws IOException if an error occurs */ - @AfterTest + @AfterEach public void cleanup() throws IOException { Files.deleteIfExists(CEN_TOO_LARGE_ZIP); Files.deleteIfExists(INVALID_CEN_SIZE); @@ -113,11 +118,11 @@ public void shouldRejectTooLargeCenSize() throws IOException { Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_SIZE_TOO_LARGE); + assertEquals(INVALID_CEN_SIZE_TOO_LARGE, ex.getMessage()); } /** @@ -133,11 +138,11 @@ public void shouldRejectInvalidCenSize() throws IOException { Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_BAD_SIZE); + assertEquals(INVALID_CEN_BAD_SIZE, ex.getMessage()); } /** @@ -153,11 +158,138 @@ public void shouldRejectInvalidCenOffset() throws IOException { Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP); - ZipException ex = expectThrows(ZipException.class, () -> { + ZipException ex = assertThrows(ZipException.class, () -> { new ZipFile(zip.toFile()); }); - assertEquals(ex.getMessage(), INVALID_CEN_BAD_OFFSET); + assertEquals(INVALID_CEN_BAD_OFFSET, ex.getMessage()); + } + + /** + * Validate that a 'Zip64 End of Central Directory' record (the END header) + * where the value of the 'total entries' field is larger than what fits + * in the CEN size is rejected. + * + * @throws IOException if an error occurs + */ + @ParameterizedTest + @ValueSource(longs = { + -1, // Negative + Long.MIN_VALUE, // Very negative + 0x3B / 3L - 1, // Cannot fit in test ZIP's CEN + MAX_CEN_SIZE / 3 + 1, // Too large to allocate int[] entries array + Long.MAX_VALUE // Unreasonably large + }) + public void shouldRejectBadTotalEntries(long totalEntries) throws IOException { + /** + * A small ZIP using the ZIP64 format. + * + * ZIP created using: "echo -n hello | zip zip64.zip -" + * Hex encoded using: "cat zip64.zip | xxd -ps" + * + * The file has the following structure: + * + * 0000 LOCAL HEADER #1 04034B50 + * 0004 Extract Zip Spec 2D '4.5' + * 0005 Extract OS 00 'MS-DOS' + * 0006 General Purpose Flag 0000 + * 0008 Compression Method 0000 'Stored' + * 000A Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 000E CRC 363A3020 + * 0012 Compressed Length FFFFFFFF + * 0016 Uncompressed Length FFFFFFFF + * 001A Filename Length 0001 + * 001C Extra Length 0014 + * 001E Filename '-' + * 001F Extra ID #0001 0001 'ZIP64' + * 0021 Length 0010 + * 0023 Uncompressed Size 0000000000000006 + * 002B Compressed Size 0000000000000006 + * 0033 PAYLOAD hello. + * + * 0039 CENTRAL HEADER #1 02014B50 + * 003D Created Zip Spec 1E '3.0' + * 003E Created OS 03 'Unix' + * 003F Extract Zip Spec 2D '4.5' + * 0040 Extract OS 00 'MS-DOS' + * 0041 General Purpose Flag 0000 + * 0043 Compression Method 0000 'Stored' + * 0045 Last Mod Time 5947AB78 'Mon Oct 7 21:27:48 2024' + * 0049 CRC 363A3020 + * 004D Compressed Length 00000006 + * 0051 Uncompressed Length FFFFFFFF + * 0055 Filename Length 0001 + * 0057 Extra Length 000C + * 0059 Comment Length 0000 + * 005B Disk Start 0000 + * 005D Int File Attributes 0001 + * [Bit 0] 1 Text Data + * 005F Ext File Attributes 11B00000 + * 0063 Local Header Offset 00000000 + * 0067 Filename '-' + * 0068 Extra ID #0001 0001 'ZIP64' + * 006A Length 0008 + * 006C Uncompressed Size 0000000000000006 + * + * 0074 ZIP64 END CENTRAL DIR 06064B50 + * RECORD + * 0078 Size of record 000000000000002C + * 0080 Created Zip Spec 1E '3.0' + * 0081 Created OS 03 'Unix' + * 0082 Extract Zip Spec 2D '4.5' + * 0083 Extract OS 00 'MS-DOS' + * 0084 Number of this disk 00000000 + * 0088 Central Dir Disk no 00000000 + * 008C Entries in this disk 0000000000000001 + * 0094 Total Entries 0000000000000001 + * 009C Size of Central Dir 000000000000003B + * 00A4 Offset to Central dir 0000000000000039 + * + * 00AC ZIP64 END CENTRAL DIR 07064B50 + * LOCATOR + * 00B0 Central Dir Disk no 00000000 + * 00B4 Offset to Central dir 0000000000000074 + * 00BC Total no of Disks 00000001 + * + * 00C0 END CENTRAL HEADER 06054B50 + * 00C4 Number of this disk 0000 + * 00C6 Central Dir Disk no 0000 + * 00C8 Entries in this disk 0001 + * 00CA Total Entries 0001 + * 00CC Size of Central Dir 0000003B + * 00D0 Offset to Central Dir FFFFFFFF + * 00D4 Comment Length 0000 + */ + + byte[] zipBytes = HexFormat.of().parseHex(""" + 504b03042d000000000078ab475920303a36ffffffffffffffff01001400 + 2d010010000600000000000000060000000000000068656c6c6f0a504b01 + 021e032d000000000078ab475920303a3606000000ffffffff01000c0000 + 00000001000000b011000000002d010008000600000000000000504b0606 + 2c000000000000001e032d00000000000000000001000000000000000100 + 0000000000003b000000000000003900000000000000504b060700000000 + 740000000000000001000000504b050600000000010001003b000000ffff + ffff0000 + """.replaceAll("\n","")); + + // Buffer to manipulate the above ZIP + ByteBuffer buf = ByteBuffer.wrap(zipBytes).order(ByteOrder.LITTLE_ENDIAN); + // Offset of the 'total entries' in the 'ZIP64 END CENTRAL DIR' record + // Update ZIP64 entry count to a value which cannot possibly fit in the small CEN + buf.putLong(0x94, totalEntries); + // The corresponding END field needs the ZIP64 magic value + buf.putShort(0xCA, (short) 0xFFFF); + // Write the ZIP to disk + Path zipFile = Path.of("bad-entry-count.zip"); + Files.write(zipFile, zipBytes); + + // Verify that the END header is rejected + ZipException ex = assertThrows(ZipException.class, () -> { + try (var zf = new ZipFile(zipFile.toFile())) { + } + }); + + assertEquals(INVALID_BAD_ENTRY_COUNT, ex.getMessage()); } /** From 38c1d6514881363ffa4ed20b34bd8cdfd8343f5f Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 9 Oct 2024 16:03:55 +0000 Subject: [PATCH 06/24] 8337980: Javac allows invocation of an inherited instance method from a static method Co-authored-by: Maurizio Cimadamore Reviewed-by: mcimadamore, jlahoda --- .../com/sun/tools/javac/comp/Resolve.java | 28 ++++++------------- .../javac/resolve/MethodAmbiguityCrash1.java | 23 +++++++++++++++ .../javac/resolve/MethodAmbiguityCrash1.out | 2 ++ .../javac/resolve/MethodAmbiguityCrash2.java | 26 +++++++++++++++++ .../javac/resolve/MethodAmbiguityCrash2.out | 2 ++ 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java create mode 100644 test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out create mode 100644 test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java create mode 100644 test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 5bf1bc0ead149..55293535ff840 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1853,6 +1853,10 @@ Symbol findMethod(Env env, bestSoFar, allowBoxing, useVarargs); + if (bestSoFar.kind == AMBIGUOUS) { + AmbiguityError a_err = (AmbiguityError)bestSoFar.baseSymbol(); + bestSoFar = a_err.mergeAbstracts(site); + } return bestSoFar; } // where @@ -2757,7 +2761,7 @@ Symbol resolveMethod(DiagnosticPosition pos, return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck, new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2789,7 +2793,7 @@ private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, List typeargtypes) { return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2913,7 +2917,7 @@ private Symbol resolveConstructor(MethodResolutionContext resolveContext, List typeargtypes) { return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findConstructor(pos, env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -2972,7 +2976,7 @@ Symbol resolveDiamond(DiagnosticPosition pos, return lookupMethod(env, pos, site.tsym, resolveMethodCheck, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) { @Override - Symbol doLookup(Env env, MethodResolutionPhase phase) { + Symbol lookup(Env env, MethodResolutionPhase phase) { return findDiamond(pos, env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()); @@ -3503,18 +3507,6 @@ abstract class BasicLookupHelper extends LookupHelper { super(name, site, argtypes, typeargtypes, maxPhase); } - @Override - final Symbol lookup(Env env, MethodResolutionPhase phase) { - Symbol sym = doLookup(env, phase); - if (sym.kind == AMBIGUOUS) { - AmbiguityError a_err = (AmbiguityError)sym.baseSymbol(); - sym = a_err.mergeAbstracts(site); - } - return sym; - } - - abstract Symbol doLookup(Env env, MethodResolutionPhase phase); - @Override Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { if (sym.kind.isResolutionError()) { @@ -3561,10 +3553,6 @@ ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) { abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym); Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { - if (sym.kind == AMBIGUOUS) { - AmbiguityError a_err = (AmbiguityError)sym.baseSymbol(); - sym = a_err.mergeAbstracts(site); - } //skip error reporting return sym; } diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java new file mode 100644 index 0000000000000..9e2b7e10080ff --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.java @@ -0,0 +1,23 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8337980 + * @summary Test compiler crash due to failure to resolve method ambiguity + * @compile/fail/ref=MethodAmbiguityCrash1.out -XDrawDiagnostics MethodAmbiguityCrash1.java + */ +public class MethodAmbiguityCrash1 { + + public interface A { + int op(); + } + + public abstract static class B { + abstract int op(); + } + + public abstract static class C extends B implements A { + + public static int test() { + return op(); // compile should fail here + } + } +} diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out new file mode 100644 index 0000000000000..ab94e965d598e --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash1.out @@ -0,0 +1,2 @@ +MethodAmbiguityCrash1.java:20:20: compiler.err.non-static.cant.be.ref: kindname.method, op() +1 error diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java new file mode 100644 index 0000000000000..9886e91a7f3d4 --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.java @@ -0,0 +1,26 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8337980 + * @summary Test compiler crash due to failure to resolve method ambiguity + * @compile/fail/ref=MethodAmbiguityCrash2.out -XDrawDiagnostics MethodAmbiguityCrash2.java + */ +public class MethodAmbiguityCrash2 { + + public interface A { + int op(); + } + + public abstract static class B { + public abstract int op(); + } + + public abstract static class C extends B implements A { + + public C(int x) { + } + + public C() { + this(op()); // compile should fail here + } + } +} diff --git a/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out new file mode 100644 index 0000000000000..ace3ffce9cdd7 --- /dev/null +++ b/test/langtools/tools/javac/resolve/MethodAmbiguityCrash2.out @@ -0,0 +1,2 @@ +MethodAmbiguityCrash2.java:23:18: compiler.err.cant.ref.before.ctor.called: op() +1 error From fcc9c8d570396506068e0a1d4123e32b195e6653 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 9 Oct 2024 16:45:56 +0000 Subject: [PATCH 07/24] 8341854: Incorrect clearing of ZF in fast_unlock_lightweight on x86 Reviewed-by: stefank, aboldtch, pchilanomate, dcubed --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 839745f76ec6a..aba5344b7e434 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -822,7 +822,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, } movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor); - testl(monitor, monitor); // Fast Unlock ZF = 0 + orl(t, 1); // Fast Unlock ZF = 0 jmpb(slow_path); // Recursive unlock. From a24525b67b97d38a33e42871bd2e8d03cd327568 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 9 Oct 2024 17:21:59 +0000 Subject: [PATCH 08/24] 8339320: Optimize ClassFile Utf8EntryImpl#inflate Reviewed-by: liach --- .../classfile/impl/AbstractPoolEntry.java | 109 +++++++++--------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 4a1803598ffa4..447e7e25c45f1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -246,66 +246,69 @@ private void inflate() { this.contentHash = hash; charLen = rawLen; state = State.BYTE; + } else { + inflateNonAscii(singleBytes, hash); } - else { - char[] chararr = new char[rawLen]; - int chararr_count = singleBytes; - // Inflate prefix of bytes to characters - JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); - - int px = offset + singleBytes; - int utfend = offset + rawLen; - while (px < utfend) { - int c = (int) rawBytes[px] & 0xff; - switch (c >> 4) { - case 0, 1, 2, 3, 4, 5, 6, 7: { - // 0xxx xxxx - px++; - chararr[chararr_count++] = (char) c; - hash = 31 * hash + c; - break; + } + + private void inflateNonAscii(int singleBytes, int hash) { + char[] chararr = new char[rawLen]; + int chararr_count = singleBytes; + // Inflate prefix of bytes to characters + JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); + + int px = offset + singleBytes; + int utfend = offset + rawLen; + while (px < utfend) { + int c = (int) rawBytes[px] & 0xff; + switch (c >> 4) { + case 0, 1, 2, 3, 4, 5, 6, 7: { + // 0xxx xxxx + px++; + chararr[chararr_count++] = (char) c; + hash = 31 * hash + c; + break; + } + case 12, 13: { + // 110x xxxx 10xx xxxx + px += 2; + if (px > utfend) { + throw malformedInput(utfend); } - case 12, 13: { - // 110x xxxx 10xx xxxx - px += 2; - if (px > utfend) { - throw malformedInput(utfend); - } - int char2 = rawBytes[px - 1]; - if ((char2 & 0xC0) != 0x80) { - throw malformedInput(px); - } - char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); - chararr[chararr_count++] = v; - hash = 31 * hash + v; - break; + int char2 = rawBytes[px - 1]; + if ((char2 & 0xC0) != 0x80) { + throw malformedInput(px); } - case 14: { - // 1110 xxxx 10xx xxxx 10xx xxxx - px += 3; - if (px > utfend) { - throw malformedInput(utfend); - } - int char2 = rawBytes[px - 2]; - int char3 = rawBytes[px - 1]; - if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { - throw malformedInput(px - 1); - } - char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); - chararr[chararr_count++] = v; - hash = 31 * hash + v; - break; + char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; + } + case 14: { + // 1110 xxxx 10xx xxxx 10xx xxxx + px += 3; + if (px > utfend) { + throw malformedInput(utfend); } - default: - // 10xx xxxx, 1111 xxxx - throw malformedInput(px); + int char2 = rawBytes[px - 2]; + int char3 = rawBytes[px - 1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { + throw malformedInput(px - 1); + } + char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; } + default: + // 10xx xxxx, 1111 xxxx + throw malformedInput(px); } - this.contentHash = hash; - charLen = chararr_count; - this.chars = chararr; - state = State.CHAR; } + this.contentHash = hash; + charLen = chararr_count; + this.chars = chararr; + state = State.CHAR; } private ConstantPoolException malformedInput(int px) { From 3ab519f16381ab49353e67db8480ed13f52ca3e8 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Oct 2024 17:30:28 +0000 Subject: [PATCH 09/24] 8341424: GHA: Collect hs_errs from build time failures Reviewed-by: ihse, jwaters --- .github/scripts/gen-build-failure-report.sh | 21 +++++++++++ .github/scripts/gen-test-results.sh | 19 +++------- .github/scripts/report-utils.sh | 41 +++++++++++++++++++++ 3 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 .github/scripts/report-utils.sh diff --git a/.github/scripts/gen-build-failure-report.sh b/.github/scripts/gen-build-failure-report.sh index fd3215fc7fe2d..c8336a5f7a1f9 100644 --- a/.github/scripts/gen-build-failure-report.sh +++ b/.github/scripts/gen-build-failure-report.sh @@ -24,12 +24,19 @@ # questions. # +# Import common utils +. report-utils.sh + GITHUB_STEP_SUMMARY="$1" BUILD_DIR="$(ls -d build/*)" # Send signal to the do-build action that we failed touch "$BUILD_DIR/build-failure" +# Collect hs_errs for build-time crashes, e.g. javac, jmod, jlink, CDS. +# These usually land in make/ +hs_err_files=$(ls make/hs_err*.log 2> /dev/null || true) + ( echo '### :boom: Build failure summary' echo '' @@ -46,6 +53,20 @@ touch "$BUILD_DIR/build-failure" echo '' echo '' + for hs_err in $hs_err_files; do + echo "
View HotSpot error log: "$hs_err"" + echo '' + echo '```' + echo "$hs_err:" + echo '' + cat "$hs_err" + echo '```' + echo '
' + echo '' + done + echo '' echo ':arrow_right: To see the entire test log, click the job in the list to the left. To download logs, see the `failure-logs` [artifact above](#artifacts).' ) >> $GITHUB_STEP_SUMMARY + +truncate_summary diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh index 9e85eef4dc08d..6c6cbaa3740f6 100644 --- a/.github/scripts/gen-test-results.sh +++ b/.github/scripts/gen-test-results.sh @@ -24,6 +24,9 @@ # questions. # +# Import common utils +. report-utils.sh + GITHUB_STEP_SUMMARY="$1" test_suite_name=$(cat build/run-test-prebuilt/test-support/test-last-ids.txt) @@ -89,18 +92,6 @@ for test in $failures $errors; do fi done >> $GITHUB_STEP_SUMMARY -# With many failures, the summary can easily exceed 1024 kB, the limit set by Github -# Trim it down if so. -summary_size=$(wc -c < $GITHUB_STEP_SUMMARY) -if [[ $summary_size -gt 1000000 ]]; then - # Trim to below 1024 kB, and cut off after the last detail group - head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp - mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY - ( - echo '' - echo ':x: **WARNING: Summary is too large and has been truncated.**' - echo '' - ) >> $GITHUB_STEP_SUMMARY -fi - echo ':arrow_right: To see the entire test log, click the job in the list to the left.' >> $GITHUB_STEP_SUMMARY + +truncate_summary diff --git a/.github/scripts/report-utils.sh b/.github/scripts/report-utils.sh new file mode 100644 index 0000000000000..da5b6c04b3cbe --- /dev/null +++ b/.github/scripts/report-utils.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +function truncate_summary() { + # With large hs_errs, the summary can easily exceed 1024 kB, the limit set by Github + # Trim it down if so. + summary_size=$(wc -c < $GITHUB_STEP_SUMMARY) + if [[ $summary_size -gt 1000000 ]]; then + # Trim to below 1024 kB, and cut off after the last detail group + head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp + mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY + ( + echo '' + echo ':x: **WARNING: Summary is too large and has been truncated.**' + echo '' + ) >> $GITHUB_STEP_SUMMARY + fi +} From 3180aaa370de16eb1835e1f57664b9fb15a6bb01 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 9 Oct 2024 17:44:15 +0000 Subject: [PATCH 10/24] 8341832: Incorrect continuation address of synthetic SIGSEGV for APX in product builds Reviewed-by: thartmann, sviswanathan, kvn --- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 2549feb8a4069..038797924a92d 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -437,6 +437,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ cmpl(rax, 0x80000); __ jcc(Assembler::notEqual, vector_save_restore); +#ifndef PRODUCT bool save_apx = UseAPX; VM_Version::set_apx_cpuFeatures(); UseAPX = true; @@ -453,6 +454,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movq(Address(rsi, 8), r31); UseAPX = save_apx; +#endif #endif __ bind(vector_save_restore); // From 593c27e69703875115e6db5843a3743ba9bd8c18 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 9 Oct 2024 18:17:53 +0000 Subject: [PATCH 11/24] 8341535: sun/awt/font/TestDevTransform.java fails with RuntimeException: Different rendering Reviewed-by: mbaesken --- test/jdk/sun/awt/font/TestDevTransform.java | 31 +++++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/test/jdk/sun/awt/font/TestDevTransform.java b/test/jdk/sun/awt/font/TestDevTransform.java index 035cb0b13d73a..2783401c0f2db 100644 --- a/test/jdk/sun/awt/font/TestDevTransform.java +++ b/test/jdk/sun/awt/font/TestDevTransform.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4269775 + * @bug 4269775 8341535 * @summary Check that different text rendering APIs agree */ @@ -46,6 +46,8 @@ import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import java.io.File; import java.util.HashMap; public class TestDevTransform { @@ -105,17 +107,34 @@ static void init(Graphics2D g2d) { g2d.setFont(font); } - static void compare(BufferedImage bi1, BufferedImage bi2) { + static void compare(BufferedImage bi1, String name1, BufferedImage bi2, String name2) throws Exception { + int nonWhite1 = 0; + int nonWhite2 = 0; + int differences = 0; + int whitePixel = Color.white.getRGB(); for (int x = 0; x < bi1.getWidth(); x++) { for (int y = 0; y < bi1.getHeight(); y++) { + int pix1 = bi1.getRGB(x, y); + int pix2 = bi2.getRGB(x, y); + if (pix1 != whitePixel) { nonWhite1++; } + if (pix2 != whitePixel) { nonWhite2++; } if (bi1.getRGB(x, y) != bi2.getRGB(x, y)) { - throw new RuntimeException("Different rendering"); + differences++; } } } + int nonWhite = (nonWhite1 < nonWhite2) ? nonWhite1 : nonWhite2; + if (differences > 0 && ((nonWhite / differences) < 20)) { + ImageIO.write(bi1, "png", new File(name1 + ".png")); + ImageIO.write(bi2, "png", new File(name2 + ".png")); + System.err.println("nonWhite image 1 = " + nonWhite1); + System.err.println("nonWhite image 2 = " + nonWhite2); + System.err.println("Number of non-white differing pixels=" + differences); + throw new RuntimeException("Different rendering: " + differences + " pixels differ."); + } } - public static void main(String args[]) { + public static void main(String args[]) throws Exception { BufferedImage tl_Image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); { @@ -149,7 +168,7 @@ public static void main(String args[]) { draw(gv_g2d, gv, 10f, 36f, .33f); } - compare(tl_Image, st_Image); - compare(gv_Image, st_Image); + compare(tl_Image, "textlayout", st_Image, "string"); + compare(gv_Image, "glyphvector", st_Image, "string"); } } From a45abf131be9ee52828c5db18a18847c45ae6994 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 9 Oct 2024 18:20:52 +0000 Subject: [PATCH 12/24] 8341860: ProblemList applications/ctw/modules/java_base_2.java on linux-x64 Reviewed-by: azvegint --- 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 3ff450dc3ad92..e85b742a53b8b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,6 +43,8 @@ # :hotspot_compiler +applications/ctw/modules/java_base_2.java 8341831 linux-x64 + compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all From 52eded4a9ce612a978ae15d5b606784bcf671c69 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 9 Oct 2024 20:31:02 +0000 Subject: [PATCH 13/24] 8341170: Open source several Choice related tests (part 2) Reviewed-by: honkar --- .../awt/Choice/ChoiceDragEventsInside.java | 210 ++++++++++++++++++ .../java/awt/Choice/ChoiceMouseEventTest.java | 123 ++++++++++ .../jdk/java/awt/Choice/ChoiceRemoveTest.java | 111 +++++++++ .../awt/Choice/PopupMenuOnChoiceArea.java | 106 +++++++++ .../java/awt/Choice/ScrollbarFlickers.java | 85 +++++++ 5 files changed, 635 insertions(+) create mode 100644 test/jdk/java/awt/Choice/ChoiceDragEventsInside.java create mode 100644 test/jdk/java/awt/Choice/ChoiceMouseEventTest.java create mode 100644 test/jdk/java/awt/Choice/ChoiceRemoveTest.java create mode 100644 test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java create mode 100644 test/jdk/java/awt/Choice/ScrollbarFlickers.java diff --git a/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java new file mode 100644 index 0000000000000..dde773f19289c --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6251983 6722236 + * @summary MouseDragged events not triggered for Choice when dragging it with left mouse button + * @key headful + * @run main ChoiceDragEventsInside + */ + +import java.awt.Choice; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceDragEventsInside extends Frame { + Robot robot; + Choice choice1; + Point pt; + Dimension size; + volatile boolean mouseDragged = false; + volatile boolean mouseDraggedOutside = false; + + public void setupUI() { + setTitle("Choce Drag Events Inside"); + choice1 = new Choice(); + for (int i = 1; i < 50; i++) { + choice1.add("item-0" + i); + } + choice1.setForeground(Color.red); + choice1.setBackground(Color.red); + choice1.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me) { + System.out.println(me); + } + + public void mouseDragged(MouseEvent me) { + System.out.println(me); + mouseDragged = true; + if (me.getY() < 0) { + mouseDraggedOutside = true; + } + } + } + ); + add(choice1); + setLayout(new FlowLayout()); + setSize(200, 200); + setLocationRelativeTo(null); + setVisible(true); + validate(); + } + + public void start() { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + robot.delay(100); + EventQueue.invokeAndWait(() -> { + pt = choice1.getLocationOnScreen(); + size = choice1.getSize(); + }); + testDragInsideChoice(InputEvent.BUTTON1_MASK); + testDragInsideChoiceList(InputEvent.BUTTON1_MASK); + testDragOutsideChoice(InputEvent.BUTTON1_MASK); + } catch (Throwable e) { + throw new RuntimeException("Test failed. Exception thrown: " + e); + } + } + + public void testDragInsideChoice(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 4, pt.y + size.height / 2); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 4, pt.y + size.height / 2, + pt.x + size.width * 3 / 4, pt.y + size.height / 2); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events inside Choice itself"); + } else { + System.out.println("Stage 1 passed. Choice generates MouseDragged events inside Choice itself"); + } + mouseDragged = false; + //close opened choice + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + } + + public void testDragInsideChoiceList(int button) { + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + robot.mousePress(button); + robot.mouseRelease(button); + robot.delay(200); + + robot.mouseMove(pt.x + size.width / 2, pt.y + 5 * size.height); + robot.delay(200); + robot.mousePress(button); + + dragMouse(pt.x + size.width / 2, pt.y + 5 * size.height, + pt.x + size.width / 2, pt.y + 8 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (mouseDragged) { + throw new RuntimeException("Test failed. Choice shouldn't generate MouseDragged events inside Choice's list"); + } else { + System.out.println("Stage 2 passed. Choice doesn't generate MouseDragged events inside Choice's list"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void testDragOutsideChoice(int button) { + pt = choice1.getLocationOnScreen(); + robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2); + robot.delay(100); + + robot.mousePress(button); + //drag mouse outside of Choice + dragMouse(pt.x + size.width / 2, pt.y + size.height / 2, + pt.x + size.width / 2, pt.y - 3 * size.height); + robot.mouseRelease(button); + robot.delay(200); + if (!mouseDragged || !mouseDraggedOutside) { + throw new RuntimeException("Test failed. Choice should generate MouseDragged events outside Choice"); + } else { + System.out.println("Stage 3 passed. Choice generates MouseDragged events outside Choice"); + } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(200); + mouseDragged = false; + } + + public void dragMouse(int x0, int y0, int x1, int y1) { + int curX = x0; + int curY = y0; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + + while (curX != x1) { + curX += dx; + robot.mouseMove(curX, curY); + } + while (curY != y1) { + curY += dy; + robot.mouseMove(curX, curY); + } + } + + public static void main(final String[] args) throws InterruptedException, + InvocationTargetException { + ChoiceDragEventsInside app = new ChoiceDragEventsInside(); + try { + EventQueue.invokeAndWait(app::setupUI); + app.start(); + } finally { + EventQueue.invokeAndWait(app::dispose); + } + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java new file mode 100644 index 0000000000000..9603d5c763de4 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4319246 + * @summary Tests that MouseReleased, MouseClicked and MouseDragged are triggered on choice + * @key headful + * @run main ChoiceMouseEventTest + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + + +public class ChoiceMouseEventTest extends Frame { + static volatile boolean mousePressed = false; + static volatile boolean mouseReleased = false; + static volatile boolean mouseClicked = false; + Choice choice = new Choice(); + static Point location; + static Dimension size; + + public void setupGUI() { + setTitle("Choice Mouse Event Test"); + this.setLayout(new BorderLayout()); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + choice.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseClicked = true; + } + + @Override + public void mousePressed(MouseEvent e) { + mousePressed = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseReleased = true; + } + }); + setLocationRelativeTo(null); + setSize(400, 200); + setVisible(true); + } + + public Point _location() { + return choice.getLocationOnScreen(); + } + + public Dimension _size() { + return choice.getSize(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + ChoiceMouseEventTest test = new ChoiceMouseEventTest(); + try { + EventQueue.invokeAndWait(test::setupGUI); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + location = test._location(); + size = test._size(); + }); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 10, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(2000); + robot.waitForIdle(); + if (!mouseClicked || !mousePressed || !mouseReleased) { + throw new RuntimeException(String.format("One of the events not arrived: " + + "mouseClicked = %b, mousePressed = %b, mouseReleased = %b", + mouseClicked, mousePressed, mouseReleased)); + } + } finally { + if (test != null) { + EventQueue.invokeAndWait(test::dispose); + } + } + } +} + diff --git a/test/jdk/java/awt/Choice/ChoiceRemoveTest.java b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java new file mode 100644 index 0000000000000..6de66db936276 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4079027 + * @summary Removing an item dynamically from a Choice object breaks lower items. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceRemoveTest + */ + +import java.awt.Choice; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ItemEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceRemoveTest extends Frame { + Choice selector; + static final String INSTRUCTIONS = """ + After window 'Choice Remove Test' appears wait for three seconds + and then click on the choice. In popup there should be no + 'Choice A' variant. Try selecting each variant with mouse + and verify by the log that the correct variant gets selected. + If after selecting item in the list the correct item gets selected + and correct item name appears in the log press Pass otherwise press Fail. + """; + + public static void main(String[] argv) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ChoiceRemoveTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + public ChoiceRemoveTest() { + super("Choice Remove Test"); + Panel p; + Label prompt; + + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + new Thread(() -> { + try { + Thread.sleep(2000); + } catch (InterruptedException ignore) { + } + removeFirst(); + }).start(); + } + }); + + setLayout(new GridLayout()); + p = new Panel(); + + prompt = new Label("Select different items including the last one"); + p.add(prompt); + + selector = new Choice(); + selector.add("Choice A"); + selector.add("Choice B"); + selector.add("Choice C"); + selector.add("Choice D"); + selector.add("Choice E"); + selector.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + Object selected = e.getItem(); + PassFailJFrame.log(selected.toString()); + } + }); + p.add(selector); + add(p); + pack(); + } + + public void removeFirst() { + selector.remove("Choice A"); + } +} diff --git a/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java new file mode 100644 index 0000000000000..2a56d7281ee44 --- /dev/null +++ b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6240046 + * @summary REG:Choice's Drop-down does not disappear when clicking somewhere, after popup menu is disposed-XTkt + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PopupMenuOnChoiceArea + */ + + +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.PopupMenu; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +public class PopupMenuOnChoiceArea extends Frame { + static final String INSTRUCTIONS = """ + You would see a window named 'Popup menu on choice area' + with Choice in it. Move the mouse pointer to the choice. + Click right mouse button on it. + You should see a popup menu with 'File' in it. + Close this popup menu by pressing Esc. + Click the left mouse button on the Choice. + You should see a Choice drop-down menu. + Move mouse pointer into drop-down menu. + Click right mouse button on any item in it. + If you see a 'File' popup menu press Fail. + If Choice drop-down closes instead press Pass. + """; + + public PopupMenuOnChoiceArea() { + super("Popup menu on choice area"); + this.setLayout(new FlowLayout()); + Choice choice = new Choice(); + choice.add("item-1"); + choice.add("item-2"); + choice.add("item-3"); + choice.add("item-4"); + add("Center", choice); + Menu fileMenu = new Menu("File"); + Menu open = new Menu("Open"); + Menu save = new Menu("save"); + CheckboxMenuItem exit = new CheckboxMenuItem("Exit"); + fileMenu.add(open); + fileMenu.add(save); + fileMenu.add(exit); + final PopupMenu pop = new PopupMenu(); + pop.setLabel("This is a popup menu"); + pop.setName("a menu"); + pop.add(fileMenu); + choice.add(pop); + choice.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + pop.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + setSize(200, 200); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(PopupMenuOnChoiceArea::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/ScrollbarFlickers.java b/test/jdk/java/awt/Choice/ScrollbarFlickers.java new file mode 100644 index 0000000000000..c35d4900134fa --- /dev/null +++ b/test/jdk/java/awt/Choice/ScrollbarFlickers.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6405707 + * @summary Choice popup & scrollbar gets Flickering when mouse is pressed & drag on the scrollbar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarFlickers + */ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class ScrollbarFlickers extends Frame { + static final String INSTRUCTIONS = """ + Open the choice popup. Select any item in it and + drag it with the mouse above or below the choice. + Keep the choice opened. + Continue dragging the mouse outside of the choice + making content of the popup scroll. + If you see that scrollbar flickers press Fail. + Otherwise press Pass. + """; + + public ScrollbarFlickers() { + super("Scrollbar Flickering Test"); + Choice ch = new Choice(); + setLayout(new BorderLayout()); + ch.add("Praveen"); + ch.add("Mohan"); + ch.add("Rakesh"); + ch.add("Menon"); + ch.add("Girish"); + ch.add("Ramachandran"); + ch.add("Elancheran"); + ch.add("Subramanian"); + ch.add("Raju"); + ch.add("Pallath"); + ch.add("Mayank"); + ch.add("Joshi"); + ch.add("Sundar"); + ch.add("Srinivas"); + ch.add("Mandalika"); + ch.add("Suresh"); + ch.add("Chandar"); + add(ch); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Test Instructions") + .testUI(ScrollbarFlickers::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} From 49c7148d3770c1ba2cd291f7b55ad471577ee151 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 9 Oct 2024 21:45:47 +0000 Subject: [PATCH 14/24] 8341366: Suspicious check in Locale.getDisplayName(Locale inLocale) Reviewed-by: naoto --- src/java.base/share/classes/java/util/Locale.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 73132b81c09a6..5550d399a7fbd 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -2324,12 +2324,11 @@ public String getDisplayName(Locale inLocale) { // If we cannot get the message format pattern, then we use a simple // hard-coded pattern. This should not occur in practice unless the // installation is missing some core files (FormatData etc.). - StringBuilder result = new StringBuilder(); - result.append((String)displayNames[1]); - if (displayNames.length > 2) { - result.append(" ("); - result.append((String)displayNames[2]); - result.append(')'); + StringBuilder result = new StringBuilder((String) displayNames[1]); + if (displayNames[2] != null) { + result.append(" (") + .append((String) displayNames[2]) + .append(')'); } return result.toString(); } From e7045e9399c5bca0592afc5769432414ecae7219 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 9 Oct 2024 21:46:50 +0000 Subject: [PATCH 15/24] 8341684: Typo in External Specifications link of java.util.Currency Reviewed-by: liach, naoto, srl --- src/java.base/share/classes/java/util/Currency.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index 14d1cf4351d97..b11b774e6142a 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ * with {@code Currency} or monetary values as it provides better handling of floating * point numbers and their operations. * - * @spec http://www.iso.org/iso/home/standards/currency_codes.htm ISO - ISO 4217 - Currency codes + * @spec https://www.iso.org/iso-4217-currency-codes.html ISO - ISO 4217 - Currency codes * @see java.math.BigDecimal * @since 1.4 */ From 172f74466fe59ece816764112dba98e4604706b7 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 9 Oct 2024 22:10:32 +0000 Subject: [PATCH 16/24] 8340985: Open source some Desktop related tests Reviewed-by: abhiscxk --- .../java/awt/Desktop/ActionSupportTest.java | 201 ++++++++++++++++++ test/jdk/java/awt/Desktop/BrowseTest.java | 90 ++++++++ .../java/awt/Desktop/DesktopSupportTest.java | 59 +++++ test/jdk/java/awt/Desktop/MailTest.java | 116 ++++++++++ test/jdk/java/awt/Desktop/OpenTest.java | 114 ++++++++++ 5 files changed, 580 insertions(+) create mode 100644 test/jdk/java/awt/Desktop/ActionSupportTest.java create mode 100644 test/jdk/java/awt/Desktop/BrowseTest.java create mode 100644 test/jdk/java/awt/Desktop/DesktopSupportTest.java create mode 100644 test/jdk/java/awt/Desktop/MailTest.java create mode 100644 test/jdk/java/awt/Desktop/OpenTest.java diff --git a/test/jdk/java/awt/Desktop/ActionSupportTest.java b/test/jdk/java/awt/Desktop/ActionSupportTest.java new file mode 100644 index 0000000000000..e5cdec0e42246 --- /dev/null +++ b/test/jdk/java/awt/Desktop/ActionSupportTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @key headful + * @summary Verifies the supported actions on different platforms. + * @library /test/lib + * @run main/othervm ActionSupportTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.net.URI; +import javax.swing.JMenuBar; +import jtreg.SkippedException; + +import static java.awt.desktop.QuitStrategy.NORMAL_EXIT; + +public class ActionSupportTest { + + public static void main(String[] args) { + final File file = new File("nonExistentFile"); + final URI uri = URI.create("nonExistentSchema:anything"); + final StringBuilder error = new StringBuilder(); + + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + } + + Desktop desktop = Desktop.getDesktop(); + for (Desktop.Action action : Desktop.Action.values()) { + boolean supported = desktop.isSupported(action); + + try { + switch (action) { + case OPEN: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.open(file); + break; + case EDIT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.edit(file); + break; + case PRINT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.print(file); + break; + case MAIL: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.mail(uri); + break; + case BROWSE: + if (supported) { + continue; // prevent native message about strange schema + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browse(uri); + break; + case APP_EVENT_FOREGROUND: + case APP_EVENT_HIDDEN: + case APP_EVENT_REOPENED: + case APP_EVENT_SCREEN_SLEEP: + case APP_EVENT_SYSTEM_SLEEP: + case APP_EVENT_USER_SESSION: + continue; // Has no effect if SystemEventListener's sub-type + // is unsupported on the current platform. + case APP_ABOUT: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setAboutHandler(e -> { + }); + break; + case APP_PREFERENCES: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPreferencesHandler(e -> { + }); + break; + case APP_OPEN_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenFileHandler(e -> { + }); + break; + case APP_PRINT_FILE: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setPrintFileHandler(e -> { + }); + break; + case APP_OPEN_URI: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setOpenURIHandler(e -> { + }); + break; + case APP_QUIT_HANDLER: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitHandler((e, response) -> { + }); + break; + case APP_QUIT_STRATEGY: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setQuitStrategy(NORMAL_EXIT); + break; + case APP_SUDDEN_TERMINATION: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.enableSuddenTermination(); + break; + case APP_REQUEST_FOREGROUND: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.requestForeground(true); + break; + case APP_HELP_VIEWER: + if (supported) { + continue; // prevent open separate window + } + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.openHelpViewer(); + break; + case APP_MENU_BAR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.setDefaultMenuBar(new JMenuBar()); + break; + case BROWSE_FILE_DIR: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.browseFileDirectory(file); + break; + case MOVE_TO_TRASH: + // if not supported, an UnsupportedOperationException will be thrown. + // if supported, other exception might be thrown. + desktop.moveToTrash(file); + break; + } + // no exception has been thrown. + if (!supported) { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but no exception has been thrown\n"); + } + } catch (UnsupportedOperationException uoe) { + if (!supported) { + System.out.println("Action " + action.name() + "is not supported."); + } else { + error.append("Action " + action.name() + " is a " + + "supported operation, " + + "but UnsupportedOperationException has been thrown\n"); + } + } catch (Exception e) { + if (supported) { + System.out.println("Action " + action.name() + "supported."); + } else { + error.append("Action " + action.name() + " is an " + + "unsupported operation, but " + + "UnsupportedOperationException has not been thrown\n"); + } + } + } + + if (!error.isEmpty()) { + System.err.println(error); + throw new RuntimeException("One or more tests failed. " + + "Look at the error output for details"); + } + System.out.println("Test completed"); + } +} diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java new file mode 100644 index 0000000000000..1bdccace3fc87 --- /dev/null +++ b/test/jdk/java/awt/Desktop/BrowseTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of method browse(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BrowseTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class BrowseTest extends JPanel { + static final String INSTRUCTIONS = """ + This test could launch default file manager to open user's home + directory, and default web browser to show the URL of java vendor. + After test execution close the native file manager and web browser + windows if they were launched by test. + Also check output for any unexpected EXCEPTIONS, + if you see any failure messages press Fail otherwise press Pass. + """; + + public BrowseTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + URI dirURI = new File(System.getProperty("user.home")).toURI(); + URI webURI = URI.create(System.getProperty("java.vendor.url", "http://www.java.com")); + boolean failed = false; + try { + PassFailJFrame.log("Try to browse " + dirURI + " ..."); + desktop.browse(dirURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + PassFailJFrame.log("Try to browse " + webURI + " ..."); + desktop.browse(webURI); + PassFailJFrame.log("Succeed.\n"); + } catch (Exception e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Browser Test") + .splitUI(BrowseTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/DesktopSupportTest.java b/test/jdk/java/awt/Desktop/DesktopSupportTest.java new file mode 100644 index 0000000000000..ec8b82ba5ef21 --- /dev/null +++ b/test/jdk/java/awt/Desktop/DesktopSupportTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @key headful + * @summary Verifies if class Desktop is supported on current platform. + * @run main DesktopSupportTest + */ + +import java.awt.Desktop; + +public class DesktopSupportTest { + public static void main(String[] args) { + boolean supported = Desktop.isDesktopSupported(); + try { + Desktop desktop = Desktop.getDesktop(); + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform."); + } + } catch (UnsupportedOperationException uoe) { + if (supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should NOT be thrown, as this class is supported " + + "on current platform."); + } + } catch (Exception e) { + if (!supported) { + throw new RuntimeException("UnsupportedOperationException " + + "should be thrown, as this class is not supported " + + "on current platform. But " + e.getClass().getName() + + " has been thrown instead."); + } + } + } +} diff --git a/test/jdk/java/awt/Desktop/MailTest.java b/test/jdk/java/awt/Desktop/MailTest.java new file mode 100644 index 0000000000000..15e5c0769a0dc --- /dev/null +++ b/test/jdk/java/awt/Desktop/MailTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of methods mail() and mail(java.net.URI uri). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MailTest + */ + +import java.awt.Desktop; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import javax.swing.JPanel; + +public class MailTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could launch the mail client to compose mail + with and without filling the message fields. + After test execution close the mail composing windows if they + were launched by test. + If you see any unexpected EXCEPTION messages in the output + press Fail. Otherwise press Pass. + """; + + private MailTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Farther testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + if (!desktop.isSupported(Desktop.Action.MAIL)) { + PassFailJFrame.log("Action.MAIL is not supported."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: launch the mail composing window without a mailto URI. + */ + try { + desktop.mail(); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: launch the mail composing window with a mailto URI. + */ + URI testURI = null; + try { + testURI = new URI("mailto", "foo@bar.com?subject=test subject" + + "&cc=foocc@bar.com&body=test body", null); + desktop.mail(testURI); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } catch (java.net.URISyntaxException use) { + // Should not reach here. + PassFailJFrame.log("EXCEPTION: " + use.getMessage()); + } + + /* + * Part 3: try to launch the mail composing window with a URI with a + * scheme which is not "mailto": + * http://java.net. + * An IOException should be thrown in this case. + */ + try { + testURI = URI.create("http://java.com"); + PassFailJFrame.log("Try to mail: " + testURI); + desktop.mail(testURI); + } catch (IllegalArgumentException e) { + PassFailJFrame.log("Caught expected IllegalArgumentException"); + } catch (IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(MailTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Desktop/OpenTest.java b/test/jdk/java/awt/Desktop/OpenTest.java new file mode 100644 index 0000000000000..1ed29067d50e1 --- /dev/null +++ b/test/jdk/java/awt/Desktop/OpenTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6255196 + * @summary Verifies the function of method open(java.io.File file). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual/othervm OpenTest + */ + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class OpenTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test could open the user's home directory and a .txt file. + After test execution, close the native application windows that + are used to open the directory and .txt file if they were launched + by the test. + If you see any unexpected EXCEPTION messages in the output press Fail. + Otherwise press Pass. + """; + + public OpenTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Further testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + /* + * Part 1: open a directory, which should launch the system default + * file explorer. + * + * On Windows platforms, the default file explorer is explorer; + * on UNIX platforms with Gnome installed and running, the default + * file explorer is Nautilus. + */ + File userHome = new File(System.getProperty("user.home")); + + try { + PassFailJFrame.log("Try to open " + userHome); + desktop.open(userHome); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + /* + * Part 2: open a normal .txt file, which should launch the registered + * application for .txt files. + */ + // Create a temp .txt file for test. + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file"); + testFile = File.createTempFile("JDIC-test", ".txt", + new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + } catch (java.io.IOException ioe) { + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.log("Failed to create test file"); + } + + try { + PassFailJFrame.log("Try to open " + testFile); + desktop.open(testFile); + PassFailJFrame.log("Succeed."); + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Mail Test") + .splitUI(OpenTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} From c850ecb20a095cb69da81f6fbe5da9c4bce66e77 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 9 Oct 2024 23:50:18 +0000 Subject: [PATCH 17/24] 8341755: Optimize argNames in InnerClassLambdaMetafactory Co-authored-by: Chen Liang Reviewed-by: liach, redestad --- .../invoke/InnerClassLambdaMetafactory.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 884f27796e7aa..10f282065fd8f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -34,12 +34,10 @@ import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; -import java.lang.classfile.FieldBuilder; import java.lang.classfile.MethodBuilder; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.constant.ClassDesc; -import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Modifier; import java.util.LinkedHashSet; @@ -51,16 +49,15 @@ import java.lang.classfile.attribute.ExceptionsAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.MethodRefEntry; + import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS; import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import static java.lang.invoke.MethodType.methodType; import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.MethodTypeDescImpl; import jdk.internal.constant.ReferenceClassDescImpl; +import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; /** @@ -71,7 +68,7 @@ */ /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$"; - private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"}; private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC; // For dumping generated classes to disk, for debugging purposes @@ -96,7 +93,6 @@ private final MethodTypeDesc implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" private final MethodType constructorType; // Generated class constructor type "(CC)void" private final MethodTypeDesc constructorTypeDesc;// Type descriptor for the generated class constructor type "(CC)void" - private final String[] argNames; // Generated names for the constructor arguments private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" private final ConstantPoolBuilder pool = ConstantPoolBuilder.of(); @@ -174,18 +170,24 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implKind == MethodHandleInfo.REF_invokeSpecial || implKind == MethodHandleInfo.REF_invokeStatic && implClass.isHidden(); int parameterCount = factoryType.parameterCount(); + ClassDesc[] argDescs; + MethodTypeDesc constructorTypeDesc; if (parameterCount > 0) { - argNames = new String[parameterCount]; argDescs = new ClassDesc[parameterCount]; for (int i = 0; i < parameterCount; i++) { - argNames[i] = "arg$" + (i + 1); argDescs[i] = classDesc(factoryType.parameterType(i)); } + constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); } else { - argNames = EMPTY_STRING_ARRAY; argDescs = EMPTY_CLASSDESC_ARRAY; + constructorTypeDesc = MTD_void; } - constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); + this.argDescs = argDescs; + this.constructorTypeDesc = constructorTypeDesc; + } + + private static String argName(int i) { + return i < ARG_NAME_CACHE.length ? ARG_NAME_CACHE[i] : "arg$" + (i + 1); } private static String lambdaClassName(Class targetClass) { @@ -313,7 +315,7 @@ public void accept(ClassBuilder clb) { .withInterfaceSymbols(interfaces); // Generate final fields to be filled in by constructor for (int i = 0; i < argDescs.length; i++) { - clb.withField(argNames[i], argDescs[i], ACC_PRIVATE | ACC_FINAL); + clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL); } generateConstructor(clb); @@ -396,7 +398,7 @@ public void accept(CodeBuilder cob) { for (int i = 0; i < parameterCount; i++) { cob.aload(0) .loadLocal(TypeKind.from(factoryType.parameterType(i)), cob.parameterSlot(i)) - .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } cob.return_(); } @@ -448,7 +450,7 @@ public void accept(CodeBuilder cob) { cob.dup() .loadConstant(i) .aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i])); cob.aastore(); } @@ -505,9 +507,9 @@ public void accept(CodeBuilder cob) { cob.ldc(cp.constantDynamicEntry(cp.bsmEntry(cp.methodHandleEntry(BSM_CLASS_DATA), List.of()), cp.nameAndTypeEntry(DEFAULT_NAME, CD_MethodHandle))); } - for (int i = 0; i < argNames.length; i++) { + for (int i = 0; i < argDescs.length; i++) { cob.aload(0) - .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argName(i), argDescs[i]))); } convertArgumentTypes(cob, methodType); From 475f8f94e038e10c796b5d56f939384d7b84da54 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 10 Oct 2024 00:03:08 +0000 Subject: [PATCH 18/24] 8341859: Optimize ClassFile Benchmark Write Reviewed-by: liach --- .../org/openjdk/bench/jdk/classfile/Write.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Write.java b/test/micro/org/openjdk/bench/jdk/classfile/Write.java index 5a966afaebff3..6e041cf64361e 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Write.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Write.java @@ -62,6 +62,15 @@ "--enable-preview", "--add-exports", "java.base/jdk.internal.classfile.impl=ALL-UNNAMED"}) public class Write { + static final int REPEATS = 40; + static final String[] METHOD_NAMES; + static { + var names = new String[REPEATS]; + for (int xi = 0; xi < REPEATS; ++xi) { + names[xi] = "main" + ((xi == 0) ? "" : "" + xi); + } + METHOD_NAMES = names; + } static String checkFileAsm = "/tmp/asw/MyClass.class"; static String checkFileBc = "/tmp/byw/MyClass.class"; static boolean writeClassAsm = Files.exists(Paths.get(checkFileAsm).getParent()); @@ -90,8 +99,8 @@ public byte[] asmStream() { mv.visitEnd(); } - for (int xi = 0; xi < 40; ++xi) { - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, "main"+ ((xi==0)? "" : ""+xi), "([Ljava/lang/String;)V", null, null); + for (int xi = 0; xi < REPEATS; ++xi) { + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, METHOD_NAMES[xi], "([Ljava/lang/String;)V", null, null); mv.visitCode(); Label loopTop = new Label(); Label loopEnd = new Label(); @@ -146,8 +155,8 @@ public byte[] jdkTree() { .return_() ) ); - for (int xi = 0; xi < 40; ++xi) { - cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, + for (int xi = 0; xi < REPEATS; ++xi) { + cb.withMethod(METHOD_NAMES[xi], MTD_void_StringArray, ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { java.lang.classfile.Label loopTop = c0.newLabel(); From 9d621d3914b39cfdcda97274a7af5ca0fe062d35 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 10 Oct 2024 01:04:02 +0000 Subject: [PATCH 19/24] 8338884: java/nio/file/attribute/BasicFileAttributeView/CreationTime.java#tmp fails on alinux3 Reviewed-by: sgehwolf, bpb --- make/test/JtregNativeJdk.gmk | 2 + .../BasicFileAttributeView/CreationTime.java | 38 +++--- .../CreationTimeHelper.java | 61 +++++++++ .../libCreationTimeHelper.c | 117 ++++++++++++++++++ 4 files changed, 200 insertions(+), 18 deletions(-) create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java create mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index d9f1e334a5cf8..90055cb5c0114 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,6 +115,8 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false + # nio tests' libCreationTimeHelper native needs -ldl linker flag + BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index ad85da7ae63b1..65e801b0a9f35 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +26,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime */ /* @test id=cwd * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using the test scratch directory, the test * scratch directory maybe at diff disk partition to /tmp on linux. - * @library ../.. /test/lib - * @build jdk.test.lib.Platform - * @run main CreationTime . + * @library ../.. /test/lib /java/foreign + * @build jdk.test.lib.Platform NativeTestHelper + * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . */ import java.lang.foreign.Linker; @@ -51,8 +52,6 @@ public class CreationTime { - private static final java.io.PrintStream err = System.err; - /** * Reads the creationTime attribute */ @@ -78,14 +77,9 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); - // If the file system doesn't support birth time, then skip this test - if (creationTime.toMillis() == 0) { - throw new SkippedException("birth time not support for: " + file); - } else { - err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); - } + System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); + System.err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); } /** @@ -107,7 +101,12 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); + try { + supportsCreationTimeRead = CreationTimeHelper. + linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); + } catch (Throwable e) { + supportsCreationTimeRead = false; + } // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -122,8 +121,11 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) + if (!current.equals(creationTime)) { + System.err.println("current = " + current); + System.err.println("creationTime = " + creationTime); throw new RuntimeException("Creation time should not have changed"); + } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java new file mode 100644 index 0000000000000..592aeba322dd0 --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; + +public class CreationTimeHelper extends NativeTestHelper { + + static { + System.loadLibrary("CreationTimeHelper"); + } + + final static Linker abi = Linker.nativeLinker(); + static final SymbolLookup lookup = SymbolLookup.loaderLookup(); + final static MethodHandle methodHandle = abi. + downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), + FunctionDescriptor.of(C_BOOL, C_POINTER)); + + // Helper so as to determine birth time support or not on Linux. + // Support is determined in a two-step process: + // 1. Determine if `statx` system call is available. If available proceed, + // otherwise return false. + // 2. Perform an actual `statx` call on the given file and check for birth + // time support in the mask returned from the call. This is needed, + // since some file systems, like nfs/tmpfs etc., don't support birth + // time even though the `statx` system call is available. + static boolean linuxIsCreationTimeSupported(String file) throws Throwable { + if (!abi.defaultLookup().find("statx").isPresent()) { + return false; + } + try (var arena = Arena.ofConfined()) { + MemorySegment s = arena.allocateFrom(file); + return (boolean)methodHandle.invokeExact(s); + } + } +} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c new file mode 100644 index 0000000000000..d4c41d8cf917a --- /dev/null +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "export.h" +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT RTLD_LOCAL +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + */ +struct my_statx_timestamp { + __int64_t tv_sec; + __uint32_t tv_nsec; + __int32_t __reserved; +}; + +/* + * struct statx used by statx system call on >= glibc 2.28 + * systems + */ +struct my_statx +{ + __uint32_t stx_mask; + __uint32_t stx_blksize; + __uint64_t stx_attributes; + __uint32_t stx_nlink; + __uint32_t stx_uid; + __uint32_t stx_gid; + __uint16_t stx_mode; + __uint16_t __statx_pad1[1]; + __uint64_t stx_ino; + __uint64_t stx_size; + __uint64_t stx_blocks; + __uint64_t stx_attributes_mask; + struct my_statx_timestamp stx_atime; + struct my_statx_timestamp stx_btime; + struct my_statx_timestamp stx_ctime; + struct my_statx_timestamp stx_mtime; + __uint32_t stx_rdev_major; + __uint32_t stx_rdev_minor; + __uint32_t stx_dev_major; + __uint32_t stx_dev_minor; + __uint64_t __statx_pad2[14]; +}; + +typedef int statx_func(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf); + +static statx_func* my_statx_func = NULL; +#endif //#defined(__linux__) + +// static boolean linuxIsCreationTimeSupported(char* file) +EXPORT bool linuxIsCreationTimeSupported(char* file) { +#if defined(__linux__) + struct my_statx stx = {0}; + int ret, atflag = AT_SYMLINK_NOFOLLOW; + unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; + + my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); + if (my_statx_func == NULL) { + return false; + } + + if (file == NULL) { + printf("input file error!\n"); + return false; + } + + ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); + if (ret != 0) { + return false; + } + // On some systems where statx is available but birth time might still not + // be supported as it's file system specific. The only reliable way to + // check for supported or not is looking at the filled in STATX_BTIME bit + // in the returned statx buffer mask. + if ((stx.stx_mask & STATX_BTIME) != 0) + return true; + return false; +#else + return false; +#endif +} From 313f4a962148331c9958618054109284470d1c9f Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 10 Oct 2024 05:40:21 +0000 Subject: [PATCH 20/24] 8340809: Open source few more AWT PopupMenu tests Reviewed-by: prr, aivanov --- .../awt/PopupMenu/ActivePopupCrashTest.java | 220 ++++++++++++++++++ .../java/awt/PopupMenu/KeyTraversalCrash.java | 126 ++++++++++ .../awt/PopupMenu/MultiplePopupMenusTest.java | 86 +++++++ .../java/awt/PopupMenu/PopupMenuCrash.java | 106 +++++++++ test/jdk/java/awt/PopupMenu/StressTest.java | 142 +++++++++++ 5 files changed, 680 insertions(+) create mode 100644 test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java create mode 100644 test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java create mode 100644 test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupMenuCrash.java create mode 100644 test/jdk/java/awt/PopupMenu/StressTest.java diff --git a/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java new file mode 100644 index 0000000000000..51c12964e6295 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import java.util.Hashtable; + +/* + * @test + * @bug 4214550 + * @summary Tests that there is no seg fault on repeatedly showing + * PopupMenu by right-clicking Label, Panel or Button + * @key headful + * @run main ActivePopupCrashTest + */ + +public class ActivePopupCrashTest { + private static Frame f; + private static Label l; + private static Button b; + private static Panel p; + + private static volatile Point labelCenter; + private static volatile Point buttonCenter; + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(ActivePopupCrashTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + labelCenter = getCenterPoint(l); + buttonCenter = getCenterPoint(b); + panelCenter = getCenterPoint(p); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(labelCenter.x, labelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(buttonCenter.x, buttonCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x, panelCenter.y); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + } + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(panelCenter.x - 5, panelCenter.y - 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static Point getCenterPoint(Component component) { + Point p = component.getLocationOnScreen(); + Dimension size = component.getSize(); + return new Point(p.x + size.width / 2, p.y + size.height / 2); + } + + public static void createAndShowUI() { + f = new Frame("ActivePopupCrashTest Test"); + MenuItem item = new MenuItem("file-1"); + item.addActionListener(ActivePopupCrashTest::logActionEvent); + Menu m = new Menu("file"); + m.add(item); + item = new MenuItem("file-2"); + m.add(item); + MenuBar mb = new MenuBar(); + mb.add(m); + + f.setMenuBar(mb); + f.setSize(200, 200); + f.setLayout(new BorderLayout()); + + l = new Label("label"); + addPopup(l, "label"); + f.add(l, BorderLayout.NORTH); + + p = new Panel(); + addPopup(p, "panel"); + f.add(p, BorderLayout.CENTER); + + b = new Button("button"); + addPopup(b, "button"); + f.add(b, BorderLayout.SOUTH); + + f.setSize(400, 300); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + static void addPopup(Component c, String name) { + PopupMenu pm = new PopupMenu(); + MenuItem mi = new MenuItem(name + "-1"); + mi.addActionListener(ActivePopupCrashTest::logActionEvent); + pm.add(mi); + + mi = new MenuItem(name + "-2"); + pm.add(mi); + + setHash(c, pm); + c.add(pm); + c.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + mouseAction("mouseClicked", e); + } + + @Override + public void mousePressed(MouseEvent e) { + mouseAction("mousePressed", e); + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseAction("mouseReleased", e); + } + }); + } + + static void logActionEvent(ActionEvent e) { + System.out.println("actionPerformed, event=" + e + ", mod=" + getMods(e)); + System.out.println("command=" + e.getActionCommand()); + System.out.println("param=" + e.paramString()); + System.out.println("source=" + e.getSource()); + } + + static String getMods(ActionEvent e) { return getMods(e.getModifiers()); } + + static String getMods(MouseEvent e) { return getMods(e.getModifiers()); } + + static String getMods(int mods) { + String modstr = ""; + if ((mods & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { + modstr += (" SHIFT"); + } else if ((mods & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK) { + modstr += (" ALT"); + } else if ((mods & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { + modstr += (" CTRL"); + } else if ((mods & ActionEvent.META_MASK) == ActionEvent.META_MASK) { + modstr += (" META"); + } + return modstr; + } + + static void mouseAction(String which, MouseEvent e) { + Component c = e.getComponent(); + System.out.println(which + " e = " + e + " , mods = " + getMods(e) + + " , component = " + c); + if (e.isPopupTrigger()) { + System.out.println("isPopup"); + PopupMenu pm = getHash(c); + pm.show(c, c.getWidth() / 2, c.getHeight() / 2); + } + } + + static Hashtable popupTable = new Hashtable<>(); + + static void setHash(Component c, PopupMenu p) { + popupTable.put(c, p); + } + + static PopupMenu getHash(Component c) { + return popupTable.get(c); + } + +} diff --git a/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java new file mode 100644 index 0000000000000..4d1d4e8f8319b --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 5021183 + * @summary Tests Key Traversal doesn't crash PopupMenu + * @key headful + * @run main KeyTraversalCrash + */ + +public class KeyTraversalCrash { + private static Frame f; + private static Label label; + + private static volatile Point loc; + private static volatile Dimension dim; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(KeyTraversalCrash::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + loc = label.getLocationOnScreen(); + dim = label.getSize(); + }); + + robot.mouseMove(loc.x + 20, loc.y + 20); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(loc.x + 25, loc.y + 25); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.keyPress(KeyEvent.VK_LEFT); + robot.keyRelease(KeyEvent.VK_LEFT); + + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + + // To close the popup, otherwise test fails on windows with timeout error + robot.mouseMove(loc.x + dim.width - 20, loc.y + dim.height - 20); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("KeyTraversalCrash Test"); + final PopupMenu popup = new PopupMenu(); + for (int i = 0; i < 10; i++) { + Menu menu = new Menu("Menu " + i); + for(int j = 0; j < 10; j++) { + MenuItem menuItem = new MenuItem("MenuItem " + j); + menu.add(menuItem); + } + popup.add(menu); + } + label = new Label("Label"); + f.add(label); + f.add(popup); + label.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + f.setSize(200, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java new file mode 100644 index 0000000000000..f939186ca072e --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTEvent; +import java.awt.Button; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4186663 4265525 + * @summary Tests that multiple PopupMenus cannot appear at the same time + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiplePopupMenusTest + */ + +public class MultiplePopupMenusTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click the right mouse button on the button + If multiple popups appear at the same time the + test fails else passes. + """; + + PassFailJFrame.builder() + .title("MultiplePopupMenusTest Instruction") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(MultiplePopupMenusTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame fr = new Frame("MultiplePopupMenusTest Test"); + TestButton button = new TestButton("button"); + fr.add(button); + fr.setSize(200, 200); + return fr; + } + + static class TestButton extends Button { + public TestButton(String title) { + super(title); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + } + + @Override + public void processMouseEvent(MouseEvent e) { + if (e.isPopupTrigger()) { + for (int i = 0; i < 10; i++) { + PopupMenu pm = new PopupMenu("Popup " + i); + pm.add(new MenuItem("item 1")); + pm.add(new MenuItem("item 2")); + add(pm); + pm.show(this, e.getX() + i * 5, e.getY() + i * 5); + } + } + super.processMouseEvent(e); + } + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java new file mode 100644 index 0000000000000..7ba738b21d276 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4281273 + * @summary PopupMenu crashed in Java. Simplified testcase. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @run main/manual PopupMenuCrash + */ + +public class PopupMenuCrash { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This tests a windows specific problem. + When you see a frame titled "PopupMenuCrash Test", right-click on it + several times for a few seconds. Then wait about 10 seconds before the + PopupMenus start to appear. Then dispose them one by one by clicking on them. + When PopupMenus do not appear anymore, press Pass. + In case of a failure, you'll see a crash. + """; + + PassFailJFrame.builder() + .title("PopupMenuCrash Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PopupMenuCrash::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + final Frame f = new Frame("PopupMenuCrash Test"); + f.setLayout(new FlowLayout()); + f.add(new Label("Press right mouse button inside this frame.")); + f.add(new Label("A pop-up menu should appear.")); + f.addMouseListener(new MouseAdapter() { + PopupMenu popup; + boolean firstPress = true; + + @Override + public void mousePressed(MouseEvent evt) { + if (firstPress) { + firstPress = false; + try { + Thread.sleep(10000); + } catch (InterruptedException ignored) { + } + } + + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + popup = new PopupMenu("Popup Menu Title"); + MenuItem mi = new MenuItem("MenuItem"); + popup.add(mi); + f.add(popup); + popup.show(evt.getComponent(), evt.getX(), evt.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent evt) { + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + if (popup != null) { + f.remove(popup); + popup = null; + } + } + } + }); + + f.setSize(400, 350); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/StressTest.java b/test/jdk/java/awt/PopupMenu/StressTest.java new file mode 100644 index 0000000000000..221aa252aa0b7 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/StressTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Robot; + +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4083400 + * @key headful + * @summary Tests that excessive popping up and down does not crash or + * throw an exception. + * @run main StressTest + */ + +public class StressTest { + private static Frame fr; + private static PopupTestPanel panel; + + private static volatile Point panelCenter; + + public static void main(String[] args) throws Exception { + final int REPEAT_COUNT = 5; + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + EventQueue.invokeAndWait(StressTest::createAndShowUI); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point loc = panel.getLocationOnScreen(); + Dimension dim = panel.getSize(); + panelCenter = new Point(loc.x + dim.width / 2, loc.y + dim.height / 2); + }); + + for (int i = 0; i < REPEAT_COUNT; i++) { + robot.mouseMove(panelCenter.x + i * 2, panelCenter.y + i * 2); + + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mouseMove(panelCenter.x - i * 2, panelCenter.y - i * 2); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (fr != null) { + fr.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + fr = new Frame("PopupMenu Test"); + panel = new PopupTestPanel(); + fr.add(panel); + fr.setSize(300, 200); + fr.setVisible(true); + } + + static class PopupTestPanel extends Panel { + + static class Item extends MenuItem { + public Item(String text) { + super(text); + } + + public boolean isEnabled() { + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + return super.isEnabled(); + } + } + + final PopupMenu popup; + + public PopupTestPanel() { + popup = new PopupMenu(); + popup.add(new Item("Soap")); + popup.add(new Item("Sponge")); + popup.add(new Item("Flannel")); + popup.add(new Item("Mat")); + popup.add(new Item("Towel")); + add(popup); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + private void showPopup(MouseEvent e) { + popup.show((Component) e.getSource(), e.getX(), e.getY()); + } + }); + } + } +} From 780de009224b048fa51a119e1db6cc52daddaaf8 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 10 Oct 2024 05:57:39 +0000 Subject: [PATCH 21/24] 8051591: Test javax/swing/JTabbedPane/8007563/Test8007563.java fails Reviewed-by: honkar, dnguyen, psadhukhan --- test/jdk/ProblemList.txt | 1 - .../JTabbedPane/8007563/Test8007563.java | 137 ------------------ .../TestJTabbedPaneBackgroundColor.java | 137 ++++++++++++++++++ 3 files changed, 137 insertions(+), 138 deletions(-) delete mode 100644 test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java create mode 100644 test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 55ab722e34fd9..8f6b0c7466413 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -677,7 +677,6 @@ javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-al javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all -javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all diff --git a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java b/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java deleted file mode 100644 index 25d3ad41eca59..0000000000000 --- a/test/jdk/javax/swing/JTabbedPane/8007563/Test8007563.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.awt.*; -import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTabbedPane; - -import static javax.swing.UIManager.*; -import static javax.swing.SwingUtilities.*; - -/* - * @test - * @key headful - * @bug 8007563 - * @summary Tests JTabbedPane background - * @author Sergey Malenkov - */ - -public class Test8007563 implements Runnable { - private static final ArrayList LIST = new ArrayList<>(); - private static final LookAndFeelInfo[] INFO = getInstalledLookAndFeels(); - private static final CountDownLatch LATCH = new CountDownLatch(INFO.length); - private static Robot ROBOT; - - public static void main(String[] args) throws Exception { - ROBOT = new Robot(); - invokeLater(new Test8007563()); - LATCH.await(); - if (!LIST.isEmpty()) { - throw new Error(LIST.toString()); - } - } - - private static void addOpaqueError(boolean opaque) { - LIST.add(getLookAndFeel().getName() + " opaque=" + opaque); - } - - private static boolean updateLookAndFeel() { - int index = (int) LATCH.getCount() - 1; - if (index >= 0) { - try { - LookAndFeelInfo info = INFO[index]; - System.err.println("L&F: " + info.getName()); - setLookAndFeel(info.getClassName()); - return true; - } catch (Exception exception) { - exception.printStackTrace(); - } - } - return false; - } - - private JFrame frame; - private JTabbedPane pane; - - public void run() { - if (this.frame == null) { - if (!updateLookAndFeel()) { - return; - } - this.pane = new JTabbedPane(); - this.pane.setOpaque(false); - this.pane.setBackground(Color.RED); - for (int i = 0; i < 3; i++) { - this.pane.addTab("Tab " + i, new JLabel("Content area " + i)); - } - this.frame = new JFrame(getClass().getSimpleName()); - this.frame.getContentPane().setBackground(Color.BLUE); - this.frame.add(this.pane); - this.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - this.frame.setSize(400, 200); - this.frame.setLocationRelativeTo(null); - this.frame.setVisible(true); - } else { - Point point = new Point(this.pane.getWidth() - 2, 2); - convertPointToScreen(point, this.pane); - Color actual = ROBOT.getPixelColor(point.x, point.y); - - boolean opaque = this.pane.isOpaque(); - Color expected = opaque - ? this.pane.getBackground() - : this.frame.getContentPane().getBackground(); - - if (!expected.equals(actual)){ - addOpaqueError(opaque); - } - if (!opaque) { - this.pane.setOpaque(true); - this.pane.repaint(); - } else { - this.frame.dispose(); - this.frame = null; - this.pane = null; - LATCH.countDown(); - } - - } - SecondaryLoop secondaryLoop = - Toolkit.getDefaultToolkit().getSystemEventQueue() - .createSecondaryLoop(); - new Thread() { - @Override - public void run() { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - } - secondaryLoop.exit(); - invokeLater(Test8007563.this); - } - }.start(); - secondaryLoop.enter(); - } -} diff --git a/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java new file mode 100644 index 0000000000000..d4bed5ac2dafa --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/TestJTabbedPaneBackgroundColor.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.util.ArrayList; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +/* + * @test + * @key headful + * @bug 8007563 + * @summary Tests JTabbedPane background + */ + +public class TestJTabbedPaneBackgroundColor { + private static ArrayList lafList = new ArrayList<>(); + private static JFrame frame; + private static JTabbedPane pane; + private static Robot robot; + private static volatile Dimension dim; + private static volatile Point loc; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing: " + laf.getName()); + setLookAndFeel(laf); + + try { + SwingUtilities.invokeAndWait(TestJTabbedPaneBackgroundColor::createAndShowUI); + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + loc = pane.getLocationOnScreen(); + dim = pane.getSize(); + }); + + loc = new Point(loc.x + dim.width - 2, loc.y + 2); + doTesting(loc, laf); + + if (!pane.isOpaque()) { + pane.setOpaque(true); + pane.repaint(); + } + robot.waitForIdle(); + robot.delay(500); + + doTesting(loc, laf); + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + if (!lafList.isEmpty()) { + throw new RuntimeException(lafList.toString()); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static void createAndShowUI() { + pane = new JTabbedPane(); + pane.setOpaque(false); + pane.setBackground(Color.RED); + for (int i = 0; i < 3; i++) { + pane.addTab("Tab " + i, new JLabel("Content area " + i)); + } + frame = new JFrame("Test Background Color"); + frame.getContentPane().setBackground(Color.BLUE); + frame.add(pane); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setSize(400, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void doTesting(Point p, UIManager.LookAndFeelInfo laf) { + boolean isOpaque = pane.isOpaque(); + Color actual = robot.getPixelColor(p.x, p.y); + Color expected = isOpaque + ? pane.getBackground() + : frame.getContentPane().getBackground(); + + if (!expected.equals(actual)) { + addOpaqueError(laf.getName(), isOpaque); + } + } + + private static void addOpaqueError(String lafName, boolean opaque) { + lafList.add(lafName + " opaque=" + opaque); + } +} From 36fca5d19d6c0eb0391b4a36db689d9c3aae09b1 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 10 Oct 2024 06:40:55 +0000 Subject: [PATCH 22/24] 8341882: [BACKOUT] java/nio/file/attribute/BasicFileAttributeView/CreationTime.java#tmp fails on alinux3 Reviewed-by: thartmann --- make/test/JtregNativeJdk.gmk | 2 - .../BasicFileAttributeView/CreationTime.java | 38 +++--- .../CreationTimeHelper.java | 61 --------- .../libCreationTimeHelper.c | 117 ------------------ 4 files changed, 18 insertions(+), 200 deletions(-) delete mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java delete mode 100644 test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 90055cb5c0114..d9f1e334a5cf8 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -115,8 +115,6 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false - # nio tests' libCreationTimeHelper native needs -ldl linker flag - BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index 65e801b0a9f35..ad85da7ae63b1 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,6 +1,5 @@ /* * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +25,18 @@ * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using /tmp directory. - * @library ../.. /test/lib /java/foreign - * @build jdk.test.lib.Platform NativeTestHelper - * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main CreationTime */ /* @test id=cwd * @summary Basic test for creationTime attribute on platforms/file systems * that support it, tests using the test scratch directory, the test * scratch directory maybe at diff disk partition to /tmp on linux. - * @library ../.. /test/lib /java/foreign - * @build jdk.test.lib.Platform NativeTestHelper - * @run main/othervm/native --enable-native-access=ALL-UNNAMED CreationTime . + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main CreationTime . */ import java.lang.foreign.Linker; @@ -52,6 +51,8 @@ public class CreationTime { + private static final java.io.PrintStream err = System.err; + /** * Reads the creationTime attribute */ @@ -77,9 +78,14 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - System.err.println("creationTime.toMillis() == " + creationTime.toMillis()); - System.err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); + System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); + // If the file system doesn't support birth time, then skip this test + if (creationTime.toMillis() == 0) { + throw new SkippedException("birth time not support for: " + file); + } else { + err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); + } } /** @@ -101,12 +107,7 @@ static void test(Path top) throws IOException { } } else if (Platform.isLinux()) { // Creation time read depends on statx system call support - try { - supportsCreationTimeRead = CreationTimeHelper. - linuxIsCreationTimeSupported(file.toAbsolutePath().toString()); - } catch (Throwable e) { - supportsCreationTimeRead = false; - } + supportsCreationTimeRead = Linker.nativeLinker().defaultLookup().find("statx").isPresent(); // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } @@ -121,11 +122,8 @@ static void test(Path top) throws IOException { Instant plusHour = Instant.now().plusSeconds(60L * 60L); Files.setLastModifiedTime(file, FileTime.from(plusHour)); FileTime current = creationTime(file); - if (!current.equals(creationTime)) { - System.err.println("current = " + current); - System.err.println("creationTime = " + creationTime); + if (!current.equals(creationTime)) throw new RuntimeException("Creation time should not have changed"); - } } /** diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java deleted file mode 100644 index 592aeba322dd0..0000000000000 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTimeHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; - -public class CreationTimeHelper extends NativeTestHelper { - - static { - System.loadLibrary("CreationTimeHelper"); - } - - final static Linker abi = Linker.nativeLinker(); - static final SymbolLookup lookup = SymbolLookup.loaderLookup(); - final static MethodHandle methodHandle = abi. - downcallHandle(lookup.findOrThrow("linuxIsCreationTimeSupported"), - FunctionDescriptor.of(C_BOOL, C_POINTER)); - - // Helper so as to determine birth time support or not on Linux. - // Support is determined in a two-step process: - // 1. Determine if `statx` system call is available. If available proceed, - // otherwise return false. - // 2. Perform an actual `statx` call on the given file and check for birth - // time support in the mask returned from the call. This is needed, - // since some file systems, like nfs/tmpfs etc., don't support birth - // time even though the `statx` system call is available. - static boolean linuxIsCreationTimeSupported(String file) throws Throwable { - if (!abi.defaultLookup().find("statx").isPresent()) { - return false; - } - try (var arena = Arena.ofConfined()) { - MemorySegment s = arena.allocateFrom(file); - return (boolean)methodHandle.invokeExact(s); - } - } -} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c deleted file mode 100644 index d4c41d8cf917a..0000000000000 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/libCreationTimeHelper.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -#include "export.h" -#include -#if defined(__linux__) -#include -#include -#include -#include -#include -#include -#ifndef STATX_BASIC_STATS -#define STATX_BASIC_STATS 0x000007ffU -#endif -#ifndef STATX_BTIME -#define STATX_BTIME 0x00000800U -#endif -#ifndef RTLD_DEFAULT -#define RTLD_DEFAULT RTLD_LOCAL -#endif - -/* - * Timestamp structure for the timestamps in struct statx. - */ -struct my_statx_timestamp { - __int64_t tv_sec; - __uint32_t tv_nsec; - __int32_t __reserved; -}; - -/* - * struct statx used by statx system call on >= glibc 2.28 - * systems - */ -struct my_statx -{ - __uint32_t stx_mask; - __uint32_t stx_blksize; - __uint64_t stx_attributes; - __uint32_t stx_nlink; - __uint32_t stx_uid; - __uint32_t stx_gid; - __uint16_t stx_mode; - __uint16_t __statx_pad1[1]; - __uint64_t stx_ino; - __uint64_t stx_size; - __uint64_t stx_blocks; - __uint64_t stx_attributes_mask; - struct my_statx_timestamp stx_atime; - struct my_statx_timestamp stx_btime; - struct my_statx_timestamp stx_ctime; - struct my_statx_timestamp stx_mtime; - __uint32_t stx_rdev_major; - __uint32_t stx_rdev_minor; - __uint32_t stx_dev_major; - __uint32_t stx_dev_minor; - __uint64_t __statx_pad2[14]; -}; - -typedef int statx_func(int dirfd, const char *restrict pathname, int flags, - unsigned int mask, struct my_statx *restrict statxbuf); - -static statx_func* my_statx_func = NULL; -#endif //#defined(__linux__) - -// static boolean linuxIsCreationTimeSupported(char* file) -EXPORT bool linuxIsCreationTimeSupported(char* file) { -#if defined(__linux__) - struct my_statx stx = {0}; - int ret, atflag = AT_SYMLINK_NOFOLLOW; - unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; - - my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); - if (my_statx_func == NULL) { - return false; - } - - if (file == NULL) { - printf("input file error!\n"); - return false; - } - - ret = my_statx_func(AT_FDCWD, file, atflag, mask, &stx); - if (ret != 0) { - return false; - } - // On some systems where statx is available but birth time might still not - // be supported as it's file system specific. The only reliable way to - // check for supported or not is looking at the filled in STATX_BTIME bit - // in the returned statx buffer mask. - if ((stx.stx_mask & STATX_BTIME) != 0) - return true; - return false; -#else - return false; -#endif -} From e7c5bf45f753ad6459c666a4dd4a31197b69e05e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 10 Oct 2024 07:21:05 +0000 Subject: [PATCH 23/24] 8341722: Fix some warnings as errors when building on Linux with toolchain clang Reviewed-by: cjplummer, lucy --- make/modules/jdk.hotspot.agent/Lib.gmk | 2 -- .../linux/native/libsaproc/LinuxDebuggerLocal.cpp | 1 - src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c | 4 ++-- src/jdk.jpackage/share/native/common/Log.cpp | 4 ---- test/hotspot/gtest/runtime/test_os_linux.cpp | 4 ++-- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index f0ede594d0ce8..12f1c1f2a9077 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -59,9 +59,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \ OPTIMIZATION := HIGH, \ EXTRA_HEADER_DIRS := java.base:libjvm, \ DISABLED_WARNINGS_gcc := sign-compare, \ - DISABLED_WARNINGS_gcc_LinuxDebuggerLocal.cpp := unused-variable, \ DISABLED_WARNINGS_gcc_ps_core.c := pointer-arith, \ - DISABLED_WARNINGS_gcc_symtab.c := unused-but-set-variable, \ DISABLED_WARNINGS_clang := sign-compare, \ DISABLED_WARNINGS_clang_libproc_impl.c := format-nonliteral, \ DISABLED_WARNINGS_clang_MacosxDebuggerLocal.m := unused-variable, \ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp index 962b1ae51722b..0ad95d0eac7cf 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp @@ -420,7 +420,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo jboolean isCopy; jlongArray array; jlong *regs; - int i; struct ps_prochandle* ph = get_proc_handle(env, this_obj); if (get_lwp_regs(ph, lwp_id, &gregs) != true) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index d3b4d3d1af927..c36b9e5707e61 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -356,7 +356,6 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t if (shdr->sh_type == sym_section) { ELF_SYM *syms; - int rslt; size_t size, n, j, htab_sz; // FIXME: there could be multiple data buffers associated with the @@ -390,7 +389,8 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t goto bad; } - rslt = hcreate_r(htab_sz, symtab->hash_table); + // int rslt = + hcreate_r(htab_sz, symtab->hash_table); // guarantee(rslt, "unexpected failure: hcreate_r"); // shdr->sh_link points to the section that contains the actual strings diff --git a/src/jdk.jpackage/share/native/common/Log.cpp b/src/jdk.jpackage/share/native/common/Log.cpp index 66154ee8247e2..8227bb1cce4dd 100644 --- a/src/jdk.jpackage/share/native/common/Log.cpp +++ b/src/jdk.jpackage/share/native/common/Log.cpp @@ -40,10 +40,6 @@ namespace { // variables are initialized if any. This will result in AV. To avoid such // use cases keep logging module free from static variables that require // initialization with functions called by CRT. - // - - // by default log everything - const Logger::LogLevel defaultLogLevel = Logger::LOG_TRACE; char defaultLogAppenderMemory[sizeof(StreamLogAppender)] = {}; diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 69c3d991b2a4f..387940afdf296 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -360,10 +360,10 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { EXPECT_TRUE(os::commit_memory(heap, size, false)); { - auto pretouch = [heap, size](Thread*, int) { + auto pretouch = [heap](Thread*, int) { os::pretouch_memory(heap, heap + size, os::vm_page_size()); }; - auto useMemory = [heap, size](Thread*, int) { + auto useMemory = [heap](Thread*, int) { int* iptr = reinterpret_cast(heap); for (int i = 0; i < 1000; i++) *iptr++ = i; }; From 16042556f394adfa93e54173944198397ad29dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 10 Oct 2024 08:34:10 +0000 Subject: [PATCH 24/24] 8341619: C2: remove unused StoreCM node Reviewed-by: chagedorn, thartmann, kvn --- src/hotspot/cpu/aarch64/aarch64.ad | 30 ------------ src/hotspot/cpu/arm/arm.ad | 12 ----- src/hotspot/cpu/ppc/ppc.ad | 17 ------- src/hotspot/cpu/riscv/riscv.ad | 35 -------------- src/hotspot/cpu/s390/s390.ad | 22 --------- src/hotspot/cpu/x86/x86_32.ad | 11 ----- src/hotspot/cpu/x86/x86_64.ad | 26 ----------- src/hotspot/share/adlc/forms.cpp | 1 - src/hotspot/share/adlc/formssel.cpp | 1 - src/hotspot/share/opto/classes.hpp | 1 - src/hotspot/share/opto/compile.cpp | 58 ------------------------ src/hotspot/share/opto/compile.hpp | 1 - src/hotspot/share/opto/escape.cpp | 9 +--- src/hotspot/share/opto/gcm.cpp | 18 +++----- src/hotspot/share/opto/idealKit.cpp | 20 -------- src/hotspot/share/opto/idealKit.hpp | 9 ---- src/hotspot/share/opto/lcm.cpp | 17 ------- src/hotspot/share/opto/loopTransform.cpp | 2 +- src/hotspot/share/opto/memnode.cpp | 48 +------------------- src/hotspot/share/opto/memnode.hpp | 33 +------------- src/hotspot/share/opto/output.cpp | 25 +--------- src/hotspot/share/opto/superword.cpp | 3 -- src/hotspot/share/runtime/vmStructs.cpp | 1 - 23 files changed, 12 insertions(+), 388 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index c7cae54d14c0a..4049ab1fe8073 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -6892,36 +6892,6 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions -// Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory1 mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST); - format %{ "storestore (elided)\n\t" - "strb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0(mem)); - - ins_pipe(istore_mem); -%} - -// Store CMS card-mark Immediate with intervening StoreStore -// needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory1 mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(INSN_COST * 2); - format %{ "storestore\n\t" - "dmb ishst" - "\n\tstrb zr, $mem\t# byte" %} - - ins_encode(aarch64_enc_strb0_ordered(mem)); - - ins_pipe(istore_mem); -%} - // Store Byte instruct storeB(iRegIorL2I src, memory1 mem) %{ diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 716f6d87230e1..bb81f2af5999b 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -4226,18 +4226,6 @@ instruct storeB(memoryB mem, store_RegI src) %{ ins_pipe(istore_mem_reg); %} -instruct storeCM(memoryB mem, store_RegI src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "STRB $src,$mem\t! CMS card-mark byte" %} - ins_encode %{ - __ strb($src$$Register, $mem$$Address); - %} - ins_pipe(istore_mem_reg); -%} - // Store Char/Short diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index d15f9929671ba..b5bfdf5067a12 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -6482,23 +6482,6 @@ instruct storeD(memory mem, regD src) %{ ins_pipe(pipe_class_memory); %} -//----------Store Instructions With Zeros-------------------------------------- - -instruct storeCM(memory mem, immI_0 zero) %{ - match(Set mem (StoreCM mem zero)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB #0, $mem \t// CMS card-mark byte store" %} - size(8); - ins_encode %{ - __ li(R0, 0); - // No release barrier: Oops are allowed to get visible after marking. - guarantee($mem$$base$$Register != R1_SP, "use frame_slots_bias"); - __ stb(R0, $mem$$disp, $mem$$base$$Register); - %} - ins_pipe(pipe_class_memory); -%} - // Convert oop pointer into compressed form. // Nodes for postalloc expand. diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index a76d172267004..30b8ff77be809 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -5039,41 +5039,6 @@ instruct loadConD0(fRegD dst, immD0 con) %{ ins_pipe(fp_load_constant_d); %} -// Store Instructions -// Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(STORE_COST); - format %{ "storestore (elided)\n\t" - "sb zr, $mem\t# byte, #@storeimmCM0" %} - - ins_encode %{ - __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); - %} - - ins_pipe(istore_mem); -%} - -// Store CMS card-mark Immediate with intervening StoreStore -// needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory mem) -%{ - match(Set mem (StoreCM mem zero)); - - ins_cost(ALU_COST + STORE_COST); - format %{ "membar(StoreStore)\n\t" - "sb zr, $mem\t# byte, #@storeimmCM0_ordered" %} - - ins_encode %{ - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); - %} - - ins_pipe(istore_mem); -%} - // Store Byte instruct storeB(iRegIorL2I src, memory mem) %{ diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 8181e96ecfc55..ebb2ca36a6458 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -4226,28 +4226,6 @@ instruct storeB(memory mem, iRegI src) %{ ins_pipe(pipe_class_dummy); %} -instruct storeCM(memory mem, immI_0 src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - // TODO: s390 port size(VARIABLE_SIZE); - format %{ "STC(Y) $src,$mem\t # CMS card-mark byte (must be 0!)" %} - ins_encode %{ - guarantee($mem$$index$$Register != Z_R0, "content will not be used."); - if ($mem$$index$$Register != noreg) { - // Can't use clear_mem --> load const zero and store character. - __ load_const_optimized(Z_R0_scratch, (long)0); - if (Immediate::is_uimm12($mem$$disp)) { - __ z_stc(Z_R0_scratch, $mem$$Address); - } else { - __ z_stcy(Z_R0_scratch, $mem$$Address); - } - } else { - __ clear_mem(Address($mem$$Address), 1); - } - %} - ins_pipe(pipe_class_dummy); -%} - // CHAR/SHORT // Store Char/Short diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 7aa4f6a29a116..7c9695571daec 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -6322,17 +6322,6 @@ instruct storeImmB(memory mem, immI8 src) %{ ins_pipe( ialu_mem_imm ); %} -// Store CMS card-mark Immediate -instruct storeImmCM(memory mem, immI8 src) %{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); - format %{ "MOV8 $mem,$src\t! CMS card-mark imm0" %} - opcode(0xC6); /* C6 /0 */ - ins_encode( SetInstMark, OpcP, RMopc_Mem(0x00,mem), Con8or32(src), ClearInstMark); - ins_pipe( ialu_mem_imm ); -%} - // Store Double instruct storeDPR( memory mem, regDPR1 src) %{ predicate(UseSSE<=1); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index fee265473befe..c3fa4c16e553f 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -5298,32 +5298,6 @@ instruct storeImmB(memory mem, immI8 src) ins_pipe(ialu_mem_imm); %} -// Store CMS card-mark Immediate -instruct storeImmCM0_reg(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreCM mem zero)); - - ins_cost(125); // XXX - format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %} - ins_encode %{ - __ movb($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmCM0(memory mem, immI_0 src) -%{ - match(Set mem (StoreCM mem src)); - - ins_cost(150); // XXX - format %{ "movb $mem, $src\t# CMS card-mark byte 0" %} - ins_encode %{ - __ movb($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - // Store Float instruct storeF(memory mem, regF src) %{ diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp index 068d745254e3d..c34a73ea1e13f 100644 --- a/src/hotspot/share/adlc/forms.cpp +++ b/src/hotspot/share/adlc/forms.cpp @@ -276,7 +276,6 @@ Form::DataType Form::is_load_from_memory(const char *opType) const { Form::DataType Form::is_store_to_memory(const char *opType) const { if( strcmp(opType,"StoreB")==0) return Form::idealB; - if( strcmp(opType,"StoreCM")==0) return Form::idealB; if( strcmp(opType,"StoreC")==0) return Form::idealC; if( strcmp(opType,"StoreD")==0) return Form::idealD; if( strcmp(opType,"StoreF")==0) return Form::idealF; diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 15bc7ddc67d60..ac2d3d94153f7 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3654,7 +3654,6 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { #if INCLUDE_SHENANDOAHGC "ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN", #endif - "StoreCM", "GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP", "GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN", "ClearArray" diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 8bee6279446ef..215e48ef9da9c 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -341,7 +341,6 @@ macro(Start) macro(StartOSR) macro(StoreB) macro(StoreC) -macro(StoreCM) macro(StoreD) macro(StoreF) macro(StoreI) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index fa0d39057cb12..c6b316e527760 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3061,52 +3061,6 @@ struct Final_Reshape_Counts : public StackObj { int get_inner_loop_count() const { return _inner_loop_count; } }; -// Eliminate trivially redundant StoreCMs and accumulate their -// precedence edges. -void Compile::eliminate_redundant_card_marks(Node* n) { - assert(n->Opcode() == Op_StoreCM, "expected StoreCM"); - if (n->in(MemNode::Address)->outcnt() > 1) { - // There are multiple users of the same address so it might be - // possible to eliminate some of the StoreCMs - Node* mem = n->in(MemNode::Memory); - Node* adr = n->in(MemNode::Address); - Node* val = n->in(MemNode::ValueIn); - Node* prev = n; - bool done = false; - // Walk the chain of StoreCMs eliminating ones that match. As - // long as it's a chain of single users then the optimization is - // safe. Eliminating partially redundant StoreCMs would require - // cloning copies down the other paths. - while (mem->Opcode() == Op_StoreCM && mem->outcnt() == 1 && !done) { - if (adr == mem->in(MemNode::Address) && - val == mem->in(MemNode::ValueIn)) { - // redundant StoreCM - if (mem->req() > MemNode::OopStore) { - // Hasn't been processed by this code yet. - n->add_prec(mem->in(MemNode::OopStore)); - } else { - // Already converted to precedence edge - for (uint i = mem->req(); i < mem->len(); i++) { - // Accumulate any precedence edges - if (mem->in(i) != nullptr) { - n->add_prec(mem->in(i)); - } - } - // Everything above this point has been processed. - done = true; - } - // Eliminate the previous StoreCM - prev->set_req(MemNode::Memory, mem->in(MemNode::Memory)); - assert(mem->outcnt() == 0, "should be dead"); - mem->disconnect_inputs(this); - } else { - prev = mem; - } - mem = prev->in(MemNode::Memory); - } - } -} - //------------------------------final_graph_reshaping_impl---------------------- // Implement items 1-5 from final_graph_reshaping below. void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes) { @@ -3276,18 +3230,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } - - case Op_StoreCM: - { - // Convert OopStore dependence into precedence edge - Node* prec = n->in(MemNode::OopStore); - n->del_req(MemNode::OopStore); - n->add_prec(prec); - eliminate_redundant_card_marks(n); - } - - // fall through - case Op_StoreB: case Op_StoreC: case Op_StoreI: diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 1ccfedd0d460f..6568828125fe2 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1244,7 +1244,6 @@ class Compile : public Phase { void final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes); void final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); - void eliminate_redundant_card_marks(Node* n); void handle_div_mod_op(Node* n, BasicType bt, bool is_unsigned); // Logic cone optimization. diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 6ab28eaa6eeba..b26480ba9b39a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4009,10 +4009,6 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phi --i; #ifdef ASSERT } else if (use->is_Mem()) { - if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { - // Don't move related cardmark. - continue; - } // Memory nodes should have new memory input. tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); assert(tp != nullptr, "ptr type"); @@ -4564,7 +4560,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // They overwrite memory edge corresponding to destination array, memnode_worklist.append_if_missing(use); } else if (!(op == Op_CmpP || op == Op_Conv2B || - op == Op_CastP2X || op == Op_StoreCM || + op == Op_CastP2X || op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || @@ -4703,9 +4699,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (use->is_Phi() || use->is_ClearArray()) { memnode_worklist.append_if_missing(use); } else if (use->is_Mem() && use->in(MemNode::Memory) == n) { - if (use->Opcode() == Op_StoreCM) { // Ignore cardmark stores - continue; - } memnode_worklist.append_if_missing(use); } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 9ba571b926d0d..dd51bb4709452 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -216,19 +216,13 @@ void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) { for (uint i = node->len()-1; i >= node->req(); i--) { Node* m = node->in(i); if (m == nullptr) continue; - - // Only process precedence edges that are CFG nodes. Safepoints and control projections can be in the middle of a block - if (is_CFG(m)) { - node->rm_prec(i); - if (n == nullptr) { - n = m; - } else { - assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); - n = is_dominator(n, m) ? m : n; - } + assert(is_CFG(m), "must be a CFG node"); + node->rm_prec(i); + if (n == nullptr) { + n = m; } else { - assert(node->is_Mach(), "sanity"); - assert(node->as_Mach()->ideal_Opcode() == Op_StoreCM, "must be StoreCM node"); + assert(is_dominator(n, m) || is_dominator(m, n), "one must dominate the other"); + n = is_dominator(n, m) ? m : n; } } if (n != nullptr) { diff --git a/src/hotspot/share/opto/idealKit.cpp b/src/hotspot/share/opto/idealKit.cpp index 80c4791cfd5cc..baa055bc60aeb 100644 --- a/src/hotspot/share/opto/idealKit.cpp +++ b/src/hotspot/share/opto/idealKit.cpp @@ -381,26 +381,6 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, return st; } -// Card mark store. Must be ordered so that it will come after the store of -// the oop. -Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx, - BasicType bt, - int adr_idx) { - assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); - const TypePtr* adr_type = nullptr; - debug_only(adr_type = C->get_adr_type(adr_idx)); - Node *mem = memory(adr_idx); - - // Add required edge to oop_store, optimizer does not support precedence edges. - // Convert required edge to precedence edge before allocation. - Node* st = new StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx); - - st = transform(st); - set_memory(st, adr_idx); - - return st; -} - //---------------------------- do_memory_merge -------------------------------- // The memory from one merging cvstate needs to be merged with the memory for another // join cvstate. If the join cvstate doesn't have a merged memory yet then we diff --git a/src/hotspot/share/opto/idealKit.hpp b/src/hotspot/share/opto/idealKit.hpp index 20acec4721118..727b70129ef90 100644 --- a/src/hotspot/share/opto/idealKit.hpp +++ b/src/hotspot/share/opto/idealKit.hpp @@ -234,15 +234,6 @@ class IdealKit: public StackObj { bool require_atomic_access = false, bool mismatched = false); - // Store a card mark ordered after store_oop - Node* storeCM(Node* ctl, - Node* adr, - Node* val, - Node* oop_store, - int oop_adr_idx, - BasicType bt, - int adr_idx); - // Trivial call Node* make_leaf_call(const TypeFunc *slow_call_type, address slow_call, diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 87be6a76eb202..2a40cf000d849 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -191,7 +191,6 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo break; case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -723,7 +722,6 @@ void PhaseCFG::adjust_register_pressure(Node* n, Block* block, intptr_t* recalc_ switch (iop) { case Op_StoreB: case Op_StoreC: - case Op_StoreCM: case Op_StoreD: case Op_StoreF: case Op_StoreI: @@ -1004,21 +1002,6 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, Vecto local++; // One more block-local input } ready_cnt.at_put(n->_idx, local); // Count em up - -#ifdef ASSERT - if (UseG1GC) { - if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_StoreCM ) { - // Check the precedence edges - for (uint prec = n->req(); prec < n->len(); prec++) { - Node* oop_store = n->in(prec); - if (oop_store != nullptr) { - assert(get_block_for_node(oop_store)->_dom_depth <= block->_dom_depth, "oop_store must dominate card-mark"); - } - } - } - } -#endif - // A few node types require changing a required edge to a precedence edge // before allocation. if( n->is_Mach() && n->req() > TypeFunc::Parms && diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 0bed38e5fb068..c3cc8532e7d30 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3817,7 +3817,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st break; } int opc = n->Opcode(); - if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass || opc == Op_StoreCM) { + if (opc == Op_StoreP || opc == Op_StoreN || opc == Op_StoreNKlass) { msg = "oop fills not handled"; break; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 6613918826057..27c0d16fac1b6 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3462,9 +3462,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* address = in(MemNode::Address); Node* value = in(MemNode::ValueIn); // Back-to-back stores to same address? Fold em up. Generally - // unsafe if I have intervening uses... Also disallowed for StoreCM - // since they must follow each StoreP operation. Redundant StoreCMs - // are eliminated just before matching in final_graph_reshape. + // unsafe if I have intervening uses. { Node* st = mem; // If Store 'st' has more than one use, we cannot fold 'st' away. @@ -3474,7 +3472,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { // require exactly ONE user until such time as we clone 'mem' for // each of 'mem's uses (thus making the exactly-1-user-rule hold // true). - while (st->is_Store() && st->outcnt() == 1 && st->Opcode() != Op_StoreCM) { + while (st->is_Store() && st->outcnt() == 1) { // Looking at a dead closed cycle of memory? assert(st != st->in(MemNode::Memory), "dead loop in StoreNode::Ideal"); assert(Opcode() == st->Opcode() || @@ -3781,48 +3779,6 @@ Node *StoreCNode::Ideal(PhaseGVN *phase, bool can_reshape){ return StoreNode::Ideal(phase, can_reshape); } -//============================================================================= -//------------------------------Identity--------------------------------------- -Node* StoreCMNode::Identity(PhaseGVN* phase) { - // No need to card mark when storing a null ptr - Node* my_store = in(MemNode::OopStore); - if (my_store->is_Store()) { - const Type *t1 = phase->type( my_store->in(MemNode::ValueIn) ); - if( t1 == TypePtr::NULL_PTR ) { - return in(MemNode::Memory); - } - } - return this; -} - -//============================================================================= -//------------------------------Ideal--------------------------------------- -Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){ - Node* progress = StoreNode::Ideal(phase, can_reshape); - if (progress != nullptr) return progress; - - Node* my_store = in(MemNode::OopStore); - if (my_store->is_MergeMem()) { - Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx()); - set_req_X(MemNode::OopStore, mem, phase); - return this; - } - - return nullptr; -} - -//------------------------------Value----------------------------------------- -const Type* StoreCMNode::Value(PhaseGVN* phase) const { - // Either input is TOP ==> the result is TOP (checked in StoreNode::Value). - // If extra input is TOP ==> the result is TOP - const Type* t = phase->type(in(MemNode::OopStore)); - if (t == Type::TOP) { - return Type::TOP; - } - return StoreNode::Value(phase); -} - - //============================================================================= //----------------------------------SCMemProjNode------------------------------ const Type* SCMemProjNode::Value(PhaseGVN* phase) const diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 323ab3dba7d65..1ca3a4b16ce1e 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -55,8 +55,7 @@ class MemNode : public Node { enum { Control, // When is it safe to do this load? Memory, // Chunk of memory is being loaded from Address, // Actually address, derived from base - ValueIn, // Value to store - OopStore // Preceding oop store, only in StoreCM + ValueIn // Value to store }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. @@ -777,36 +776,6 @@ class StoreNKlassNode : public StoreNNode { virtual BasicType memory_type() const { return T_NARROWKLASS; } }; -//------------------------------StoreCMNode----------------------------------- -// Store card-mark byte to memory for CM -// The last StoreCM before a SafePoint must be preserved and occur after its "oop" store -// Preceding equivalent StoreCMs may be eliminated. -class StoreCMNode : public StoreNode { - private: - virtual uint hash() const { return StoreNode::hash() + _oop_alias_idx; } - virtual bool cmp( const Node &n ) const { - return _oop_alias_idx == ((StoreCMNode&)n)._oop_alias_idx - && StoreNode::cmp(n); - } - virtual uint size_of() const { return sizeof(*this); } - int _oop_alias_idx; // The alias_idx of OopStore - -public: - StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : - StoreNode(c, mem, adr, at, val, oop_store, MemNode::release), - _oop_alias_idx(oop_alias_idx) { - assert(_oop_alias_idx >= Compile::AliasIdxRaw || - (_oop_alias_idx == Compile::AliasIdxBot && !Compile::current()->do_aliasing()), - "bad oop alias idx"); - } - virtual int Opcode() const; - virtual Node* Identity(PhaseGVN* phase); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type* Value(PhaseGVN* phase) const; - virtual BasicType memory_type() const { return T_VOID; } // unspecific - int oop_alias_idx() const { return _oop_alias_idx; } -}; - //------------------------------SCMemProjNode--------------------------------------- // This class defines a projection of the memory state of a store conditional node. // These nodes return a value, but also update memory. diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index eda0f65d6bc1f..2865cf674295b 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -1665,30 +1665,7 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } } } - } -#ifdef ASSERT - // Check that oop-store precedes the card-mark - else if (mach->ideal_Opcode() == Op_StoreCM) { - uint storeCM_idx = j; - int count = 0; - for (uint prec = mach->req(); prec < mach->len(); prec++) { - Node *oop_store = mach->in(prec); // Precedence edge - if (oop_store == nullptr) continue; - count++; - uint i4; - for (i4 = 0; i4 < last_inst; ++i4) { - if (block->get_node(i4) == oop_store) { - break; - } - } - // Note: This test can provide a false failure if other precedence - // edges have been added to the storeCMNode. - assert(i4 == last_inst || i4 < storeCM_idx, "CM card-mark executes before oop-store"); - } - assert(count > 0, "storeCM expects at least one precedence edge"); - } -#endif - else if (!n->is_Proj()) { + } else if (!n->is_Proj()) { // Remember the beginning of the previous instruction, in case // it's followed by a flag-kill and a null-check. Happens on // Intel all the time, with add-to-memory kind of opcodes. diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index bb5fed78b0274..20c8dfbff1776 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -657,9 +657,6 @@ void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, // or need to run igvn.optimize() again before SLP } else if (out->is_memory_phi() && !_vloop.in_bb(out)) { // Ditto. Not sure what else to check further. - } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) { - // StoreCM has an input edge used as a precedence edge. - // Maybe an issue when oop stores are vectorized. } else { assert(out == prev || prev == nullptr, "no branches off of store slice"); } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index e0a36330687dc..3060e225427a8 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1590,7 +1590,6 @@ declare_c2_type(StorePNode, StoreNode) \ declare_c2_type(StoreNNode, StoreNode) \ declare_c2_type(StoreNKlassNode, StoreNode) \ - declare_c2_type(StoreCMNode, StoreNode) \ declare_c2_type(SCMemProjNode, ProjNode) \ declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \