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
+}
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/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/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.
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);
//
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/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/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 dc91d6db1e398..c6b316e527760 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);
}
}
}
@@ -3055,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) {
@@ -3270,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/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/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/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/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/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/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/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();
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) \
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);
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
*/
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();
}
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/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) {
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/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;
};
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
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
+ }
+}
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;
+ }
+}
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() {
+
+ }
+ }
+}
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/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();
+ }
+}
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();
+ }
+}
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());
+ }
+ });
+ }
+ }
+}
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());
}
/**
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);
+ }
+}
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");
}
}
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
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();