From ca47f5f06daebc3c50bf47b4cdf1fcf8edf1507d Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 21 Sep 2023 08:56:31 +0000 Subject: [PATCH 01/29] 8316105: C2: Back to back Parse Predicates from different loops but with same deopt reason are wrongly grouped together Reviewed-by: roland, thartmann, kvn --- src/hotspot/share/opto/predicates.cpp | 17 +++- src/hotspot/share/opto/predicates.hpp | 5 +- .../TestBackToBackParsePredicates.java | 85 +++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/predicates/TestBackToBackParsePredicates.java diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 63e627070a1..b8bdb221a75 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -77,7 +77,7 @@ Deoptimization::DeoptReason RuntimePredicate::uncommon_trap_reason(IfProjNode* i } bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason) { - if (node->is_IfProj()) { + if (node->is_IfProj() && !node->in(0)->is_ParsePredicate()) { return deopt_reason == uncommon_trap_reason(node->as_IfProj()); } else { return false; @@ -108,6 +108,21 @@ ParsePredicateNode* ParsePredicateIterator::next() { return _parse_predicates.at(_current_index++); } +#ifdef ASSERT +// Check that the block has at most one Parse Predicate and that we only find Regular Predicate nodes (i.e. IfProj, +// If, or RangeCheck nodes). +void PredicateBlock::verify_block() { + Node* next = _parse_predicate.entry(); // Skip unique Parse Predicate of this block if present + while (next != _entry) { + assert(!next->is_ParsePredicate(), "can only have one Parse Predicate in a block"); + const int opcode = next->Opcode(); + assert(next->is_IfProj() || opcode == Op_If || opcode == Op_RangeCheck, + "Regular Predicates consist of an IfProj and an If or RangeCheck node"); + next = next->in(0); + } +} +#endif // ASSERT + // Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block // anymore (i.e. entry to the first Regular Predicate in this block if any or `regular_predicate_proj` otherwise). Node* PredicateBlock::skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason) { diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 0f5c8fe3264..d273ab09dc4 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -270,11 +270,14 @@ class PredicateBlock : public StackObj { Node* _entry; static Node* skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason); + DEBUG_ONLY(void verify_block();) public: PredicateBlock(Node* predicate_proj, Deoptimization::DeoptReason deopt_reason) : _parse_predicate(predicate_proj, deopt_reason), - _entry(skip_regular_predicates(_parse_predicate.entry(), deopt_reason)) {} + _entry(skip_regular_predicates(_parse_predicate.entry(), deopt_reason)) { + DEBUG_ONLY(verify_block();) + } // Returns the control input node into this Regular Predicate block. This is either: // - The control input to the first If node in the block representing a Runtime Predicate if there is at least one diff --git a/test/hotspot/jtreg/compiler/predicates/TestBackToBackParsePredicates.java b/test/hotspot/jtreg/compiler/predicates/TestBackToBackParsePredicates.java new file mode 100644 index 00000000000..e61bd0cead3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/TestBackToBackParsePredicates.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8316105 + * @library /test/lib + * @summary Test that back to back Parse Predicates with same deopt reason are not grouped together + * @run main/othervm -Xbatch compiler.predicates.TestBackToBackParsePredicates + */ + +package compiler.predicates; + +import jdk.test.lib.Asserts; + +public class TestBackToBackParsePredicates { + static long lFld; + + public static void main(String[] strArr2) { + for (int i = -350; i <= 0; i++) { + lFld = 30; + test(i); + check(); + } + lFld = 30; + test(1); + check(); + } + + // Inlined + static void foo() { + for (int i12 = 1; i12 < 5; i12++) { // Loop A + lFld += 1; // StoreL + } + } + + static void test(int x) { + foo(); + + // After fully unrolling loop A and after next round of IGVN: + // We wrongly treat two back to back Loop Limit Check Parse Predicates as single Predicate Block. We therefore + // keep the Loop Parse Predicate of loop A: + // + // Loop Parse Predicate (of A) + // Loop Limit Check Parse Predicate (of A) | + // -> StoreL of lFld pinned here | Wrongly treated as single Predicate Block + // Loop Limit Check Parse Predicate (of B) | + for (int i = 7; i < 212; i++) { // Loop B + for (int j = 1; j < 80; j++) { + switch (x % 8) { + case 0: + case 2: + break; + case 6: + case 7: + } + } + } + } + + static void check() { + Asserts.assertEQ(34L, lFld); + } +} From 23ed890f3ff25296fb8dbb59532b9079e0326db9 Mon Sep 17 00:00:00 2001 From: Sergei Tachenov Date: Thu, 21 Sep 2023 09:00:26 +0000 Subject: [PATCH 02/29] 6415065: Submenu is shown on wrong screen in multiple monitor environment Reviewed-by: prr --- .../share/classes/javax/swing/JMenu.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/java.desktop/share/classes/javax/swing/JMenu.java b/src/java.desktop/share/classes/javax/swing/JMenu.java index 91cb63e2ed5..0b37747484c 100644 --- a/src/java.desktop/share/classes/javax/swing/JMenu.java +++ b/src/java.desktop/share/classes/javax/swing/JMenu.java @@ -478,6 +478,23 @@ protected Point getPopupMenuOrigin() { y = 0 - yOffset - pmSize.height; // Otherwise drop 'up' } } + // Note that the position may be later adjusted to fit the menu into the screen if possible. + // However, the code that does it (JPopupMenu.adjustPopupLocationToFitScreen) has no idea which screen + // to fit into, and determines it by the position calculated here, so we need to make sure it's on + // the correct screen, otherwise the menu may appear on the wrong screen (JDK-6415065). + // (Both x and y are relative to the JMenu position here, that's why we need these +-position.x/y here.) + if (position.y + y < screenBounds.y) { // Above the current screen? + y = screenBounds.y - position.y; // The top of the screen relative to this JMenu. + } + if (position.y + y >= screenBounds.y + screenBounds.height) { // Below the current screen? + y = screenBounds.y + screenBounds.height - 1 - position.y; // The bottom of the screen... + } + if (position.x + x < screenBounds.x) { // To the left of the current screen? + x = screenBounds.x - position.x; // The left edge of the screen... + } + if (position.x + x >= screenBounds.x + screenBounds.width) { // To the right of the current screen? + x = screenBounds.x + screenBounds.width - 1 - position.x; // The right edge of the screen... + } return new Point(x,y); } From 913e43fea995b746fb9e1b25587d254396c7c3c9 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 21 Sep 2023 09:36:28 +0000 Subject: [PATCH 03/29] 8316582: Minor startup regression in 22-b15 due JDK-8310929 Reviewed-by: liach, rriggs --- .../share/classes/java/lang/StringLatin1.java | 23 +++++++++------- .../jdk/internal/util/DecimalDigits.java | 26 ++++++++++--------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 102f4c5f476..71776cca485 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -34,9 +34,7 @@ import java.util.stream.StreamSupport; import jdk.internal.util.ArraysSupport; import jdk.internal.util.DecimalDigits; -import jdk.internal.util.ByteArrayLittleEndian; import jdk.internal.vm.annotation.IntrinsicCandidate; -import jdk.internal.vm.annotation.Stable; import static java.lang.String.LATIN1; import static java.lang.String.UTF16; @@ -100,7 +98,7 @@ public static byte[] inflate(byte[] value, int off, int len) { */ static int getChars(int i, int index, byte[] buf) { // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. - int q, r; + int q; int charPos = index; boolean negative = i < 0; @@ -111,16 +109,15 @@ static int getChars(int i, int index, byte[] buf) { // Generate two digits per iteration while (i <= -100) { q = i / 100; - r = (q * 100) - i; - i = q; charPos -= 2; - ByteArrayLittleEndian.setShort(buf, charPos, DecimalDigits.digitPair(r)); + writeDigitPair(buf, charPos, (q * 100) - i); + i = q; } // We know there are at most two digits left at this point. if (i < -9) { charPos -= 2; - ByteArrayLittleEndian.setShort(buf, charPos, DecimalDigits.digitPair(-i)); + writeDigitPair(buf, charPos, -i); } else { buf[--charPos] = (byte)('0' - i); } @@ -162,7 +159,7 @@ static int getChars(long i, int index, byte[] buf) { while (i <= Integer.MIN_VALUE) { q = i / 100; charPos -= 2; - ByteArrayLittleEndian.setShort(buf, charPos, DecimalDigits.digitPair((int)((q * 100) - i))); + writeDigitPair(buf, charPos, (int)((q * 100) - i)); i = q; } @@ -172,14 +169,14 @@ static int getChars(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; - ByteArrayLittleEndian.setShort(buf, charPos, DecimalDigits.digitPair((q2 * 100) - i2)); + writeDigitPair(buf, charPos, (q2 * 100) - i2); i2 = q2; } // We know there are at most two digits left at this point. if (i2 < -9) { charPos -= 2; - ByteArrayLittleEndian.setShort(buf, charPos, DecimalDigits.digitPair(-i2)); + writeDigitPair(buf, charPos, -i2); } else { buf[--charPos] = (byte)('0' - i2); } @@ -190,6 +187,12 @@ static int getChars(long i, int index, byte[] buf) { return charPos; } + private static void writeDigitPair(byte[] buf, int charPos, int value) { + short pair = DecimalDigits.digitPair(value); + buf[charPos] = (byte)(pair); + buf[charPos + 1] = (byte)(pair >> 8); + } + public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index f55452868a6..f078c7d5726 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -57,18 +57,20 @@ public final class DecimalDigits implements Digits { * */ @Stable - private static final short[] DIGITS = new short[] { - 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, - 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, - 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, - 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, - 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, - 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, - 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, - 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, - 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, - 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939 - }; + private static final short[] DIGITS; + + static { + short[] digits = new short[10 * 10]; + + for (int i = 0; i < 10; i++) { + short hi = (short) (i + '0'); + for (int j = 0; j < 10; j++) { + short lo = (short) ((j + '0') << 8); + digits[i * 10 + j] = (short) (hi | lo); + } + } + DIGITS = digits; + } /** * Singleton instance of DecimalDigits. From 6a4b6655507582ff685a999c21e7fd3992a39816 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Thu, 21 Sep 2023 12:06:27 +0000 Subject: [PATCH 04/29] 8316659: assert(LockingMode != LM_LIGHTWEIGHT || flag == CCR0) failed: bad condition register Reviewed-by: goetz, mbaesken --- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index f3179cf6479..80c00c713d7 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2450,7 +2450,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- if (method->is_synchronized()) { - ConditionRegister r_flag = CCR1; Register r_oop = r_temp_4; const Register r_box = r_temp_5; Label done, locked; @@ -2465,8 +2464,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for locking. // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - __ compiler_fast_lock_object(r_flag, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - __ beq(r_flag, locked); + __ compiler_fast_lock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); + __ beq(CCR0, locked); // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. Inline a special case of call_VM that @@ -2659,8 +2658,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- if (method->is_synchronized()) { - - ConditionRegister r_flag = CCR1; const Register r_oop = r_temp_4; const Register r_box = r_temp_5; const Register r_exception = r_temp_6; @@ -2677,8 +2674,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for unlocking. - __ compiler_fast_unlock_object(r_flag, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - __ beq(r_flag, done); + __ compiler_fast_unlock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); + __ beq(CCR0, done); // Save and restore any potential method result value around the unlocking operation. save_native_result(masm, ret_type, workspace_slot_offset); From b3d75fe12ec74e3c2445ef2615425867ccb7d4a2 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 21 Sep 2023 12:17:34 +0000 Subject: [PATCH 05/29] 8310874: Runthese30m crashes with klass should be in the placeholders during verification Reviewed-by: dholmes, iklam --- .../share/classfile/loaderConstraints.cpp | 32 +++++++++++-------- .../share/classfile/loaderConstraints.hpp | 3 +- .../share/classfile/systemDictionary.cpp | 4 +++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/classfile/loaderConstraints.cpp b/src/hotspot/share/classfile/loaderConstraints.cpp index c447914b852..a613bb9f26d 100644 --- a/src/hotspot/share/classfile/loaderConstraints.cpp +++ b/src/hotspot/share/classfile/loaderConstraints.cpp @@ -27,15 +27,11 @@ #include "classfile/classLoaderDataGraph.hpp" #include "classfile/dictionary.hpp" #include "classfile/loaderConstraints.hpp" -#include "classfile/placeholders.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" -#include "oops/oop.inline.hpp" #include "oops/symbolHandle.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/safepoint.hpp" #include "utilities/resourceHash.hpp" // Overview @@ -447,6 +443,23 @@ InstanceKlass* LoaderConstraintTable::find_constrained_klass(Symbol* name, return nullptr; } +// Removes a class that was added to the table then class loading subsequently failed for this class, +// so we don't have a dangling pointer to InstanceKlass in the LoaderConstraintTable. +void LoaderConstraintTable::remove_failed_loaded_klass(InstanceKlass* klass, + ClassLoaderData* loader) { + + Symbol* name = klass->name(); + LoaderConstraint *p = find_loader_constraint(name, loader); + if (p != nullptr && p->klass() != nullptr && p->klass() == klass) { + // If this is the klass in the constraint, the error was OOM from the ClassLoader.addClass() call. + // Other errors during loading (eg. constraint violations) will not have added this klass. + log_info(class, loader, constraints)("removing klass %s: failed to load", name->as_C_string()); + // We only null out the class, since the constraint for the class name for this loader is still valid as + // it was added when checking signature loaders for a method or field resolution. + p->set_klass(nullptr); + } +} + void LoaderConstraintTable::merge_loader_constraints(Symbol* class_name, LoaderConstraint* p1, LoaderConstraint* p2, @@ -511,15 +524,8 @@ void LoaderConstraintTable::verify() { // We found the class in the dictionary, so we should // make sure that the Klass* matches what we already have. guarantee(k == probe->klass(), "klass should be in dictionary"); - } else { - // If we don't find the class in the dictionary, it - // has to be in the placeholders table. - PlaceholderEntry* entry = PlaceholderTable::get_entry(name, loader_data); - - // The InstanceKlass might not be on the entry, so the only - // thing we can check here is whether we were successful in - // finding the class in the placeholders table. - guarantee(entry != nullptr, "klass should be in the placeholders"); + // If we don't find the class in the dictionary, it is + // in the process of loading and may or may not be in the placeholder table. } } for (int n = 0; n< probe->num_loaders(); n++) { diff --git a/src/hotspot/share/classfile/loaderConstraints.hpp b/src/hotspot/share/classfile/loaderConstraints.hpp index bdf8fac51fa..8153d9c28fd 100644 --- a/src/hotspot/share/classfile/loaderConstraints.hpp +++ b/src/hotspot/share/classfile/loaderConstraints.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ class LoaderConstraintTable : public AllStatic { // Class loader constraints static bool check_or_update(InstanceKlass* k, ClassLoaderData* loader, Symbol* name); + static void remove_failed_loaded_klass(InstanceKlass* k, ClassLoaderData* loader); static void purge_loader_constraints(); static void print_table_statistics(outputStream* st); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index d9da1a4e843..10ceb008794 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1526,6 +1526,10 @@ InstanceKlass* SystemDictionary::find_or_define_instance_class(Symbol* class_nam } else if (HAS_PENDING_EXCEPTION) { assert(defined_k == nullptr, "Should not have a klass if there's an exception"); k->class_loader_data()->add_to_deallocate_list(k); + + // Also remove this InstanceKlass from the LoaderConstraintTable if added. + MutexLocker ml(SystemDictionary_lock); + LoaderConstraintTable::remove_failed_loaded_klass(k, class_loader_data(class_loader)); } return defined_k; } From 378bcd5985c6993c0239fcc49ae66ededd3b465c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 21 Sep 2023 12:24:51 +0000 Subject: [PATCH 06/29] 8316595: Alpine build fails after JDK-8314021 Reviewed-by: dholmes, yyang --- src/hotspot/os/linux/os_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 11869b39854..019046c4f9b 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4373,7 +4373,7 @@ jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { // the number of bytes written to out_fd is returned if transfer was successful // otherwise, returns -1 that implies an error jlong os::Linux::sendfile(int out_fd, int in_fd, jlong* offset, jlong count) { - return sendfile64(out_fd, in_fd, (off64_t*)offset, (size_t)count); + return ::sendfile64(out_fd, in_fd, (off64_t*)offset, (size_t)count); } // Determine if the vmid is the parent pid for a child in a PID namespace. From 8cbe42b94aaf2ff090ae8399da0418e9e2fc3873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 21 Sep 2023 12:39:03 +0000 Subject: [PATCH 07/29] 8316421: libjava should load shell32.dll eagerly Reviewed-by: erikj, jwaters, jvernee --- make/modules/java.base/lib/CoreLibraries.gmk | 3 +- .../windows/native/libjava/java_props_md.c | 40 +++---------------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk index 0fe8e109f45..8904c39449e 100644 --- a/make/modules/java.base/lib/CoreLibraries.gmk +++ b/make/modules/java.base/lib/CoreLibraries.gmk @@ -64,7 +64,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_macosx := -L$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/, \ - LDFLAGS_windows := -delayload:shell32.dll, \ LIBS_unix := -ljvm, \ LIBS_linux := $(LIBDL), \ LIBS_aix := $(LIBDL) $(LIBM),\ @@ -72,7 +71,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \ -framework Foundation \ -framework SystemConfiguration, \ LIBS_windows := jvm.lib \ - shell32.lib delayimp.lib \ + shell32.lib ole32.lib \ advapi32.lib version.lib, \ )) diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 2ff4c9e8806..5eefb6a9fc9 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -40,10 +40,6 @@ #include "locale_str.h" #include "java_props.h" -#ifndef VER_PLATFORM_WIN32_WINDOWS -#define VER_PLATFORM_WIN32_WINDOWS 1 -#endif - #ifndef PROCESSOR_ARCHITECTURE_AMD64 #define PROCESSOR_ARCHITECTURE_AMD64 9 #endif @@ -213,39 +209,13 @@ getHomeFromShell32() */ static WCHAR *u_path = NULL; if (u_path == NULL) { - HRESULT hr; - - /* - * SHELL32 DLL is delay load DLL and we can use the trick with - * __try/__except block. - */ - __try { - /* - * For Windows Vista and later (or patched MS OS) we need to use - * [SHGetKnownFolderPath] call to avoid MAX_PATH length limitation. - * Shell32.dll (version 6.0.6000 or later) - */ - hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &u_path); - } __except(EXCEPTION_EXECUTE_HANDLER) { - /* Exception: no [SHGetKnownFolderPath] entry */ - hr = E_FAIL; - } + WCHAR *tmpPath = NULL; + HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &tmpPath); if (FAILED(hr)) { - WCHAR path[MAX_PATH+1]; - - /* fallback solution for WinXP and Windows 2000 */ - hr = SHGetFolderPathW(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path); - if (FAILED(hr)) { - /* we can't find the shell folder. */ - u_path = NULL; - } else { - /* Just to be sure about the path length until Windows Vista approach. - * [S_FALSE] could not be returned due to [CSIDL_FLAG_DONT_VERIFY] flag and UNICODE version. - */ - path[MAX_PATH] = 0; - u_path = _wcsdup(path); - } + CoTaskMemFree(tmpPath); + } else { + u_path = tmpPath; } } return u_path; From 349723cb8dd7a5e496f348dc8689431480ef1083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 21 Sep 2023 12:43:53 +0000 Subject: [PATCH 08/29] 8315739: Missing null check in os::vm_min_address Reviewed-by: dholmes, jvernee --- src/hotspot/os/linux/os_linux.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 019046c4f9b..594898cd805 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4254,9 +4254,12 @@ size_t os::vm_min_address() { static size_t value = 0; if (value == 0) { assert(is_aligned(_vm_min_address_default, os::vm_allocation_granularity()), "Sanity"); - FILE* f = fopen("/proc/sys/vm/mmap_min_addr", "r"); - if (fscanf(f, "%zu", &value) != 1) { - value = _vm_min_address_default; + FILE* f = os::fopen("/proc/sys/vm/mmap_min_addr", "r"); + if (f != nullptr) { + if (fscanf(f, "%zu", &value) != 1) { + value = _vm_min_address_default; + } + fclose(f); } value = MAX2(_vm_min_address_default, value); } From 38bf1192b637cf3513cb25ac21f513bfb51cb55b Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Thu, 21 Sep 2023 13:54:35 +0000 Subject: [PATCH 09/29] 8310228: Improve error reporting for uncaught native exceptions on Windows Reviewed-by: dholmes, djelinski --- make/test/JtregNativeHotspot.gmk | 2 + src/hotspot/os/windows/os_windows.cpp | 57 +++++++++------ .../UncaughtNativeExceptionTest.java | 71 +++++++++++++++++++ .../ErrorHandling/libNativeException.c | 32 +++++++++ 4 files changed, 140 insertions(+), 22 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk index 84bd6b123f5..45efa033cff 100644 --- a/make/test/JtregNativeHotspot.gmk +++ b/make/test/JtregNativeHotspot.gmk @@ -1504,6 +1504,8 @@ else BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCompleteExit += -lpthread BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -ljvm -lpthread + + BUILD_HOTSPOT_JTREG_EXCLUDE += libNativeException.c endif ifeq ($(ASAN_ENABLED), true) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 5563169151b..39e6c15fed8 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -280,10 +280,12 @@ void os::run_periodic_checks(outputStream* st) { return; } +#ifndef _WIN64 // previous UnhandledExceptionFilter, if there is one static LPTOP_LEVEL_EXCEPTION_FILTER prev_uef_handler = nullptr; +#endif -LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo); +static LONG WINAPI Uncaught_Exception_Handler(struct _EXCEPTION_POINTERS* exceptionInfo); void os::init_system_properties_values() { // sysclasspath, java_home, dll_dir @@ -397,7 +399,7 @@ void os::init_system_properties_values() { #ifndef _WIN64 // set our UnhandledExceptionFilter and save any previous one - prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception); + prev_uef_handler = SetUnhandledExceptionFilter(Uncaught_Exception_Handler); #endif // Done @@ -2534,9 +2536,7 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { #if defined(_M_AMD64) || defined(_M_IX86) //----------------------------------------------------------------------------- -LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { - PCONTEXT ctx = exceptionInfo->ContextRecord; -#ifndef _WIN64 +static bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) { // handle exception caused by native method modifying control word DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; @@ -2547,34 +2547,48 @@ LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_STACK_CHECK: - case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_FLT_UNDERFLOW: { + PCONTEXT ctx = exceptionInfo->ContextRecord; +#ifndef _WIN64 jint fp_control_word = (* (jint*) StubRoutines::x86::addr_fpu_cntrl_wrd_std()); if (fp_control_word != ctx->FloatSave.ControlWord) { // Restore FPCW and mask out FLT exceptions ctx->FloatSave.ControlWord = fp_control_word | 0xffffffc0; // Mask out pending FLT exceptions ctx->FloatSave.StatusWord &= 0xffffff00; - return EXCEPTION_CONTINUE_EXECUTION; + return true; } +#else // !_WIN64 + // On Windows, the mxcsr control bits are non-volatile across calls + // See also CR 6192333 + // + jint MxCsr = INITIAL_MXCSR; + // we can't use StubRoutines::x86::addr_mxcsr_std() + // because in Win64 mxcsr is not saved there + if (MxCsr != ctx->MxCsr) { + ctx->MxCsr = MxCsr; + return true; + } +#endif // !_WIN64 + } } + return false; +} +#endif + +#ifndef _WIN64 +static LONG WINAPI Uncaught_Exception_Handler(struct _EXCEPTION_POINTERS* exceptionInfo) { + if (handle_FLT_exception(exceptionInfo)) { + return EXCEPTION_CONTINUE_EXECUTION; + } + + // we only override this on 32 bits, so only check it there if (prev_uef_handler != nullptr) { // We didn't handle this exception so pass it to the previous // UnhandledExceptionFilter. return (prev_uef_handler)(exceptionInfo); } -#else // !_WIN64 - // On Windows, the mxcsr control bits are non-volatile across calls - // See also CR 6192333 - // - jint MxCsr = INITIAL_MXCSR; - // we can't use StubRoutines::x86::addr_mxcsr_std() - // because in Win64 mxcsr is not saved there - if (MxCsr != ctx->MxCsr) { - ctx->MxCsr = MxCsr; - return EXCEPTION_CONTINUE_EXECUTION; - } -#endif // !_WIN64 return EXCEPTION_CONTINUE_SEARCH; } @@ -2831,9 +2845,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } #if defined(_M_AMD64) || defined(_M_IX86) - if ((in_java || in_native) && exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION) { - LONG result=Handle_FLT_Exception(exceptionInfo); - if (result==EXCEPTION_CONTINUE_EXECUTION) return result; + if ((in_java || in_native) && handle_FLT_exception(exceptionInfo)) { + return EXCEPTION_CONTINUE_EXECUTION; } #endif diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java new file mode 100644 index 00000000000..3f26461643a --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/UncaughtNativeExceptionTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id + * @enablePreview + * @requires os.family == "windows" + * @library /test/lib + * @run testng UncaughtNativeExceptionTest + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import org.testng.annotations.Test; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; + +import static org.testng.Assert.assertTrue; + +public class UncaughtNativeExceptionTest { + private static class Crasher { + public static void main(String[] args) throws Throwable { + System.loadLibrary("NativeException"); + throwException(); + } + + static native void throwException(); + } + + // check that we actually report the native exception, + // and don't terminate abruptly due to stack overflow error + @Test + public void testNativeExceptionReporting() throws Exception { + OutputAnalyzer output = ProcessTools.executeTestJvm( + // executeTestJvm doesn't seem to forward 'java.library.path' + "-Djava.library.path=" + System.getProperty("java.library.path"), + Crasher.class.getName()); + + File hsErrFile = HsErrFileUtils.openHsErrFileFromOutput(output); + Path hsErrPath = hsErrFile.toPath(); + assertTrue(Files.exists(hsErrPath)); + + Pattern[] positivePatterns = { + Pattern.compile(".*Internal Error \\(0x2a\\).*") + }; + HsErrFileUtils.checkHsErrFileContent(hsErrFile, positivePatterns, null, true /* check end marker */, false /* verbose */); + } +} diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c b/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c new file mode 100644 index 00000000000..3bf71cf9c67 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/libNativeException.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +#include + +const DWORD EX_CODE = 42; + +JNIEXPORT void JNICALL Java_UncaughtNativeExceptionTest_00024Crasher_throwException(JNIEnv* env, jclass cls) { + RaiseException(EX_CODE, EXCEPTION_NONCONTINUABLE, 0, NULL); +} From 3809d69ac4b3d186ccdc336949b658e4671347c8 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 21 Sep 2023 13:57:28 +0000 Subject: [PATCH 10/29] 8316240: Open source several add/remove MenuBar manual tests Reviewed-by: honkar, psadhukhan --- .../AddRemoveMenuBarTest_1.java | 104 ++++++++++ .../AddRemoveMenuBarTest_2.java | 99 +++++++++ .../AddRemoveMenuBarTest_3.java | 195 ++++++++++++++++++ .../AddRemoveMenuBarTest_4.java | 116 +++++++++++ 4 files changed, 514 insertions(+) create mode 100644 test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java create mode 100644 test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java create mode 100644 test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java create mode 100644 test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java new file mode 100644 index 00000000000..808bb598cec --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4028130 + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_1 + */ + +public class AddRemoveMenuBarTest_1 { + + private static final String INSTRUCTIONS = """ + An initially empty frame should appear. + + Click anywhere in the frame to add a menu bar at the top of the frame. + + Click again to replace the menu bar with another menu bar. + + Each menu bar has one (empty) menu, labelled with the + number of the menu bar appearing. + + After a menubar is added, the frame should not be resized nor repositioned + on the screen; + + it should have the same size and position. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_1 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(18) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_1 frame = new AddRemoveMenuBar_1(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_1 extends Frame { + int menuCount; + + AddRemoveMenuBar_1() { + super("AddRemoveMenuBar_1"); + setSize(200, 200); + menuCount = 0; + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setMenuBar(); + } + }); + } + + void setMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu(Integer.toString(menuCount++))); + setMenuBar(bar); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java new file mode 100644 index 00000000000..c0c98a5ca95 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4028130 + * @key headful + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_2 + */ + +public class AddRemoveMenuBarTest_2 { + private static final String INSTRUCTIONS = """ + A frame with a menu bar appears. + + Click anywhere in the frame to replace the menu bar with + another one. + + Each menu bar has one (empty) menu, 'foo'. + + After the menu bar replacement, the containing frame + should not be resized nor repositioned on the screen. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_2 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(15) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_2 frame = new AddRemoveMenuBar_2(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_2 extends Frame { + AddRemoveMenuBar_2() { + super("AddRemoveMenuBar_2"); + setSize(200, 200); + setMenuBar(); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setMenuBar(); + } + }); + } + + int count = 0; + + void setMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu("foo " + count++)); + super.setMenuBar(bar); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java new file mode 100644 index 00000000000..a01ddd9925b --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Checkbox; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4017504 + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_3 + */ + +public class AddRemoveMenuBarTest_3 { + private static final String INSTRUCTIONS = """ + A frame at (100,100) contains two (2) rows of three (3) text + fields each, and under this, a checkbox labelled 'Use menubar'. + + The first row's text fields pertain to the x coordinates and + the second row's text fields pertain to the y coordinates. + + The first column, 'request', is an input only field for frame + location. (press enter to apply). + + The second column, 'reported', is an output only + field reporting frame location. + + The third column, 'inset', is an output only field reporting + the frame's inset values. + + You can click the 'Use menubar' checkbox to alternately add + and remove a menu bar containing an (empty) 'Help' menu. + + After a menubar is added or removed, the frame should not + have been resized nor repositioned on the screen and the + y inset should accurately reflect the presence or absence + of the menubar within the inset. + + The insets always include the window manager's title and border + decorations, if any. + + Upon test completion, click Pass or Fail appropriately. + """; + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_3 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(30) + .columns(38) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_3 frame = new AddRemoveMenuBar_3(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(null, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_3 extends Frame { + TextField xfield; + TextField yfield; + + TextField xfield_out; + TextField yfield_out; + TextField xinset_out; + TextField yinset_out; + + Checkbox menu_checkbox; + MenuBar menubar; + + public AddRemoveMenuBar_3() { + super("AddRemoveMenuBar_3"); + + menubar = new MenuBar(); + menubar.setHelpMenu(new Menu("Help")); + + setLayout(new BorderLayout()); + Panel p = new Panel(); + add("Center", p); + p.setLayout(new GridLayout(3, 3)); + + menu_checkbox = new Checkbox("Use menubar"); + add("South", menu_checkbox); + + xfield = new TextField(); + yfield = new TextField(); + xfield_out = new TextField(); + xfield_out.setEditable(false); + xfield_out.setFocusable(false); + yfield_out = new TextField(); + yfield_out.setEditable(false); + yfield_out.setFocusable(false); + + xinset_out = new TextField(); + xinset_out.setEditable(false); + xinset_out.setFocusable(false); + yinset_out = new TextField(); + yinset_out.setEditable(false); + yinset_out.setFocusable(false); + + p.add(new Label("request")); + p.add(new Label("reported")); + p.add(new Label("inset")); + + p.add(xfield); + p.add(xfield_out); + p.add(xinset_out); + + p.add(yfield); + p.add(yfield_out); + p.add(yinset_out); + + setSize(200, 200); + setLocation(100, 100); + + addComponentListener(new ComponentAdapter() { + @Override + public void componentMoved(ComponentEvent e) { + xfield_out.setText(Integer.toString(getLocation().x)); + yfield_out.setText(Integer.toString(getLocation().y)); + + xinset_out.setText(Integer.toString(getInsets().left)); + yinset_out.setText(Integer.toString(getInsets().top)); + } + }); + + ActionListener setLocationListener = e -> { + Rectangle r = getBounds(); + try { + r.x = Integer.parseInt(xfield.getText()); + r.y = Integer.parseInt(yfield.getText()); + } catch (java.lang.NumberFormatException ignored) { + } + + setLocation(r.x, r.y); + }; + + xfield.addActionListener(setLocationListener); + yfield.addActionListener(setLocationListener); + + menu_checkbox.addItemListener(e -> { + if (menu_checkbox.getState()) { + setMenuBar(menubar); + } else { + setMenuBar(null); + } + + validate(); + xinset_out.setText(Integer.toString(getInsets().left)); + yinset_out.setText(Integer.toString(getInsets().top)); + }); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java new file mode 100644 index 00000000000..571fce7fba5 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4071086 + * @key headful + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_4 + */ + +public class AddRemoveMenuBarTest_4 { + + private static final String INSTRUCTIONS = """ + There is a frame with a menubar and a single button. + + The button is labelled 'Add new MenuBar'. + + If you click the button, the menubar is replaced with another menubar. + This can be done repeatedly. + + The -th menubar contains one menu, 'TestMenu', + with two items, 'one ' and 'two '. + + Click again to replace the menu bar with another menu bar. + + After a menubar has been replaced with another menubar, + the frame should not be resized nor repositioned on the screen. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_4 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(18) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_4 frame = new AddRemoveMenuBar_4(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_4 extends Frame { + int count = 1; + MenuBar mb = null; + + AddRemoveMenuBar_4() { + super("AddRemoveMenuBar_4"); + setLayout(new FlowLayout()); + + Button b = new Button("Add new MenuBar"); + b.addActionListener((e) -> createMenuBar()); + add(b); + + createMenuBar(); + + setSize(300, 300); + } + + void createMenuBar() { + if (mb != null) { + remove(mb); + } + + mb = new MenuBar(); + Menu m = new Menu("TestMenu" + count); + m.add(new MenuItem("one " + count)); + m.add(new MenuItem("two " + count)); + count++; + mb.add(m); + setMenuBar(mb); + } +} From 8350268c058e693b8c5fcca3b808ea97c5ddc546 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 21 Sep 2023 14:29:06 +0000 Subject: [PATCH 11/29] 8316453: [JVMCI] Using Xcomp on jargraal must eagerly initialize JVMCI Reviewed-by: never, thartmann --- src/hotspot/share/runtime/threads.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 648637b1fc0..276c3e362f0 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -699,6 +699,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Initialize JVMCI eagerly when it is explicitly requested. // Or when JVMCILibDumpJNIConfig or JVMCIPrintProperties is enabled. force_JVMCI_initialization = EagerJVMCI || JVMCIPrintProperties || JVMCILibDumpJNIConfig; + if (!force_JVMCI_initialization && UseJVMCICompiler && !UseJVMCINativeLibrary && (!UseInterpreter || !BackgroundCompilation)) { + // Force initialization of jarjvmci otherwise requests for blocking + // compilations will not actually block until jarjvmci is initialized. + force_JVMCI_initialization = true; + } if (JVMCIPrintProperties || JVMCILibDumpJNIConfig) { // Both JVMCILibDumpJNIConfig and JVMCIPrintProperties exit the VM // so compilation should be disabled. This prevents dumping or From 90bcdbd15fe7211377f6f6812a2b562c17995d65 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Sep 2023 14:47:06 +0000 Subject: [PATCH 12/29] 8316581: Improve performance of Symbol::print_value_on() Reviewed-by: shade, coleenp, dholmes --- src/hotspot/share/oops/symbol.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index f77d69fe3d4..cbb51e1bb90 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -22,7 +22,6 @@ * */ - #include "precompiled.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" @@ -390,11 +389,9 @@ void Symbol::print() const { print_on(tty); } // The print_value functions are present in all builds, to support the // disassembler and error reporting. void Symbol::print_value_on(outputStream* st) const { - st->print("'"); - for (int i = 0; i < utf8_length(); i++) { - st->print("%c", char_at(i)); - } - st->print("'"); + st->print_raw("'", 1); + st->print_raw((const char*)base(), utf8_length()); + st->print_raw("'", 1); } void Symbol::print_value() const { print_value_on(tty); } From 063790012d6c0e97d3766efad6fe5efa42586f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 21 Sep 2023 15:43:05 +0000 Subject: [PATCH 13/29] 8316433: net.dll should delay load winhttp.dll Reviewed-by: erikj, ihse --- make/modules/java.base/Lib.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk index 728773b1ccc..cc25cb8d0ae 100644 --- a/make/modules/java.base/Lib.gmk +++ b/make/modules/java.base/Lib.gmk @@ -52,7 +52,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNET, \ DISABLED_WARNINGS_microsoft_ResolverConfigurationImpl.c := 4996, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LDFLAGS_windows := -delayload:secur32.dll -delayload:iphlpapi.dll, \ + LDFLAGS_windows := -delayload:secur32.dll -delayload:iphlpapi.dll \ + -delayload:winhttp.dll, \ LIBS_unix := -ljvm -ljava, \ LIBS_linux := $(LIBDL), \ LIBS_aix := $(LIBDL),\ From 542b3000f0cd1136466066cb4046257220ac2827 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 21 Sep 2023 16:28:44 +0000 Subject: [PATCH 14/29] 8315954: getArgumentValues002.java fails on Graal Reviewed-by: never, fparain --- src/hotspot/share/interpreter/oopMapCache.cpp | 6 +- src/hotspot/share/interpreter/oopMapCache.hpp | 4 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 84 ++++++--- .../jdk/vm/ci/hotspot/CompilerToVM.java | 9 + .../ci/hotspot/HotSpotResolvedJavaMethod.java | 15 ++ .../HotSpotResolvedJavaMethodImpl.java | 12 ++ .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 1 + .../runtime/test/TestResolvedJavaMethod.java | 169 ++++++++++++++++++ 8 files changed, 278 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 2ce6ce7ca7a..17e8475fb48 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -407,6 +407,8 @@ void OopMapCacheEntry::flush() { void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) { assert(_resource_allocate_bit_mask, "Should not resource allocate the _bit_mask"); + assert(from->has_valid_mask(), + "Cannot copy entry with an invalid mask"); set_method(from->method()); set_bci(from->bci()); @@ -612,7 +614,9 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); tmp->initialize(); tmp->fill(method, bci); - entry->resource_copy(tmp); + if (tmp->has_valid_mask()) { + entry->resource_copy(tmp); + } tmp->flush(); FREE_C_HEAP_OBJ(tmp); } diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index d66ca23feb8..0c2e45036eb 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -84,7 +84,7 @@ class InterpreterOopMap: ResourceObj { private: Method* _method; // the method for which the mask is valid unsigned short _bci; // the bci for which the mask is valid - int _mask_size; // the mask size in bits + int _mask_size; // the mask size in bits (USHRT_MAX if invalid) int _expression_stack_size; // the size of the expression stack in slots protected: @@ -146,6 +146,8 @@ class InterpreterOopMap: ResourceObj { int expression_stack_size() const { return _expression_stack_size; } + // Determines if a valid mask has been computed + bool has_valid_mask() const { return _mask_size != USHRT_MAX; } }; class OopMapCache : public CHeapObj { diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 09b3cb26203..5affc354ad3 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -35,6 +35,7 @@ #include "compiler/oopMap.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" +#include "interpreter/oopMapCache.hpp" #include "jfr/jfrEvents.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciCompilerToVM.hpp" @@ -2512,7 +2513,7 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas jlongArray info = (jlongArray) JNIHandles::make_local(THREAD, info_oop); runtime->init_JavaVM_info(info, JVMCI_CHECK_0); return info; -} +C2V_END C2V_VMENTRY_PREFIX(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject c2vm)) if (thread == nullptr || thread->libjvmci_runtime() == nullptr) { @@ -2777,7 +2778,7 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool return 0L; } return (jlong) PEER_JVMCIENV->make_global(result).as_jobject(); -} +C2V_END C2V_VMENTRY_NULL(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) requireJVMCINativeLibrary(JVMCI_CHECK_NULL); @@ -2790,13 +2791,13 @@ C2V_VMENTRY_NULL(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) JVMCIENV->destroy_global(global_handle_obj); return result; -} +C2V_END C2V_VMENTRY(void, updateHotSpotNmethod, (JNIEnv* env, jobject, jobject code_handle)) JVMCIObject code = JVMCIENV->wrap(code_handle); // Execute this operation for the side effect of updating the InstalledCode state JVMCIENV->get_nmethod(code); -} +C2V_END C2V_VMENTRY_NULL(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle)) JVMCIObject code = JVMCIENV->wrap(code_handle); @@ -2812,7 +2813,7 @@ C2V_VMENTRY_NULL(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle JVMCIPrimitiveArray result = JVMCIENV->new_byteArray(code_size, JVMCI_CHECK_NULL); JVMCIENV->copy_bytes_from(code_bytes, result, 0, code_size); return JVMCIENV->get_jbyteArray(result); -} +C2V_END C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL); @@ -2828,7 +2829,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, ARGUMEN executable = Reflection::new_method(m, false, CHECK_NULL); } return JNIHandles::make_local(THREAD, executable); -} +C2V_END static InstanceKlass* check_field(Klass* klass, jint index, JVMCI_TRAPS) { if (!klass->is_instance_klass()) { @@ -2850,7 +2851,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI fieldDescriptor fd(iklass, index); oop reflected = Reflection::new_field(&fd, CHECK_NULL); return JNIHandles::make_local(THREAD, reflected); -} +C2V_END static jbyteArray get_encoded_annotation_data(InstanceKlass* holder, AnnotationArray* annotations_array, bool for_class, jint filter_length, jlong filter_klass_pointers, @@ -2964,7 +2965,7 @@ C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlo JVMCIENV->put_object_at(result, result_index++, entry); } return JVMCIENV->get_jobjectArray(result); -} +C2V_END C2V_VMENTRY_0(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) methodHandle method(THREAD, UNPACK_PAIR(Method, method)); @@ -2975,11 +2976,11 @@ C2V_VMENTRY_0(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, ARGUME method->set_method_data(method_data); } return (jlong) method_data->get_failed_speculations_address(); -} +C2V_END C2V_VMENTRY(void, releaseFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address)) FailedSpeculation::free_failed_speculations((FailedSpeculation**)(address) failed_speculations_address); -} +C2V_END C2V_VMENTRY_0(jboolean, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj)) JVMCIPrimitiveArray speculation_handle = JVMCIENV->wrap(speculation_obj); @@ -2987,7 +2988,7 @@ C2V_VMENTRY_0(jboolean, addFailedSpeculation, (JNIEnv* env, jobject, jlong faile char* speculation = NEW_RESOURCE_ARRAY(char, speculation_len); JVMCIENV->copy_bytes_to(speculation_handle, (jbyte*) speculation, 0, speculation_len); return FailedSpeculation::add_failed_speculation(nullptr, (FailedSpeculation**)(address) failed_speculations_address, (address) speculation, speculation_len); -} +C2V_END C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status)) JavaValue result(T_VOID); @@ -2999,11 +3000,11 @@ C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status)) vmSymbols::int_void_signature(), &jargs, CHECK); -} +C2V_END C2V_VMENTRY_0(jlong, ticksNow, (JNIEnv* env, jobject)) return CompilerEvent::ticksNow(); -} +C2V_END C2V_VMENTRY_0(jint, registerCompilerPhase, (JNIEnv* env, jobject, jstring jphase_name)) #if INCLUDE_JFR @@ -3013,14 +3014,14 @@ C2V_VMENTRY_0(jint, registerCompilerPhase, (JNIEnv* env, jobject, jstring jphase #else return -1; #endif // !INCLUDE_JFR -} +C2V_END C2V_VMENTRY(void, notifyCompilerPhaseEvent, (JNIEnv* env, jobject, jlong startTime, jint phase, jint compileId, jint level)) EventCompilerPhase event; if (event.should_commit()) { CompilerEvent::PhaseEvent::post(event, startTime, phase, compileId, level); } -} +C2V_END C2V_VMENTRY(void, notifyCompilerInliningEvent, (JNIEnv* env, jobject, jint compileId, ARGUMENT_PAIR(caller), ARGUMENT_PAIR(callee), jboolean succeeded, jstring jmessage, jint bci)) EventCompilerInlining event; @@ -3030,7 +3031,7 @@ C2V_VMENTRY(void, notifyCompilerInliningEvent, (JNIEnv* env, jobject, jint compi JVMCIObject message = JVMCIENV->wrap(jmessage); CompilerEvent::InlineEvent::post(event, compileId, caller, callee, succeeded, JVMCIENV->as_utf8_string(message), bci); } -} +C2V_END C2V_VMENTRY(void, setThreadLocalObject, (JNIEnv* env, jobject, jint id, jobject value)) requireInHotSpot("setThreadLocalObject", JVMCI_CHECK); @@ -3040,7 +3041,7 @@ C2V_VMENTRY(void, setThreadLocalObject, (JNIEnv* env, jobject, jint id, jobject } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d is not a valid thread local id", id)); -} +C2V_END C2V_VMENTRY_NULL(jobject, getThreadLocalObject, (JNIEnv* env, jobject, jint id)) requireInHotSpot("getThreadLocalObject", JVMCI_CHECK_NULL); @@ -3049,7 +3050,7 @@ C2V_VMENTRY_NULL(jobject, getThreadLocalObject, (JNIEnv* env, jobject, jint id)) } THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d is not a valid thread local id", id)); -} +C2V_END C2V_VMENTRY(void, setThreadLocalLong, (JNIEnv* env, jobject, jint id, jlong value)) requireInHotSpot("setThreadLocalLong", JVMCI_CHECK); @@ -3061,7 +3062,7 @@ C2V_VMENTRY(void, setThreadLocalLong, (JNIEnv* env, jobject, jint id, jlong valu THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d is not a valid thread local id", id)); } -} +C2V_END C2V_VMENTRY_0(jlong, getThreadLocalLong, (JNIEnv* env, jobject, jint id)) requireInHotSpot("getThreadLocalLong", JVMCI_CHECK_0); @@ -3073,7 +3074,49 @@ C2V_VMENTRY_0(jlong, getThreadLocalLong, (JNIEnv* env, jobject, jint id)) THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("%d is not a valid thread local id", id)); } -} +C2V_END + +C2V_VMENTRY(void, getOopMapAt, (JNIEnv* env, jobject, ARGUMENT_PAIR(method), + jint bci, jlongArray oop_map_handle)) + methodHandle method(THREAD, UNPACK_PAIR(Method, method)); + if (bci < 0 || bci >= method->code_size()) { + JVMCI_THROW_MSG(IllegalArgumentException, + err_msg("bci %d is out of bounds [0 .. %d)", bci, method->code_size())); + } + InterpreterOopMap mask; + OopMapCache::compute_one_oop_map(method, bci, &mask); + if (!mask.has_valid_mask()) { + JVMCI_THROW_MSG(IllegalArgumentException, err_msg("bci %d is not valid", bci)); + } + if (mask.number_of_entries() == 0) { + return; + } + + int nslots = method->max_locals() + method->max_stack(); + int nwords = ((nslots - 1) / 64) + 1; + JVMCIPrimitiveArray oop_map = JVMCIENV->wrap(oop_map_handle); + int oop_map_len = JVMCIENV->get_length(oop_map); + if (nwords > oop_map_len) { + JVMCI_THROW_MSG(IllegalArgumentException, + err_msg("oop map too short: %d > %d", nwords, oop_map_len)); + } + + jlong* oop_map_buf = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jlong, nwords); + if (oop_map_buf == nullptr) { + JVMCI_THROW_MSG(InternalError, err_msg("could not allocate %d longs", nwords)); + } + for (int i = 0; i < nwords; i++) { + oop_map_buf[i] = 0L; + } + + BitMapView oop_map_view = BitMapView((BitMap::bm_word_t*) oop_map_buf, nwords * BitsPerLong); + for (int i = 0; i < nslots; i++) { + if (mask.is_oop(i)) { + oop_map_view.set_bit(i); + } + } + JVMCIENV->copy_longs_from((jlong*)oop_map_buf, oop_map, 0, nwords); +C2V_END #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -3232,6 +3275,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "registerCompilerPhase", CC "(" STRING ")I", FN_PTR(registerCompilerPhase)}, {CC "notifyCompilerPhaseEvent", CC "(JIII)V", FN_PTR(notifyCompilerPhaseEvent)}, {CC "notifyCompilerInliningEvent", CC "(I" HS_METHOD2 HS_METHOD2 "ZLjava/lang/String;I)V", FN_PTR(notifyCompilerInliningEvent)}, + {CC "getOopMapAt", CC "(" HS_METHOD2 "I[J)V", FN_PTR(getOopMapAt)}, }; int CompilerToVM::methods_count() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 0ca3c731bcf..98eac1eb5bf 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1473,4 +1473,13 @@ public void close() { } } } + + /** + * @see HotSpotResolvedJavaMethod#getOopMapAt + */ + void getOopMapAt(HotSpotResolvedJavaMethodImpl method, int bci, long[] oopMap) { + getOopMapAt(method, method.getMethodPointer(), bci, oopMap); + } + + native void getOopMapAt(HotSpotResolvedJavaMethodImpl method, long methodPointer, int bci, long[] oopMap); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java index a7f80cea39a..0f5c5002e0a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java @@ -23,6 +23,7 @@ package jdk.vm.ci.hotspot; import java.lang.reflect.Modifier; +import java.util.BitSet; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -127,4 +128,18 @@ default boolean isDefault() { boolean hasCodeAtLevel(int entryBCI, int level); int methodIdnum(); + + + /** + * Computes which local variables and operand stack slots in {@code method} contain + * live object values at the instruction denoted by {@code bci}. This is the "oop map" + * used by the garbage collector for interpreter frames. + * + * @param bci the index of an instruction in this method's bytecodes + * @return the computed oop map. The first {@link #getMaxLocals} bits are for + * the local variables, the remaining bits are for the stack slots. + * @throws IllegalArgumentException if this method has no bytecode or + * {@code bci} is not the index of a bytecode instruction + */ + BitSet getOopMapAt(int bci); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 046fa1082b9..6b9381df1ec 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -35,6 +35,7 @@ import java.lang.reflect.Executable; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.BitSet; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -767,4 +768,15 @@ private List getAnnotationData0(ResolvedJavaType... filter) { byte[] encoded = compilerToVM().getEncodedExecutableAnnotationData(this, filter); return VMSupport.decodeAnnotations(encoded, AnnotationDataDecoder.INSTANCE); } + + @Override + public BitSet getOopMapAt(int bci) { + if (getCodeSize() == 0) { + throw new IllegalArgumentException("has no bytecode"); + } + int nwords = ((getMaxLocals() + getMaxStackSize() - 1) / 64) + 1; + long[] oopMap = new long[nwords]; + compilerToVM().getOopMapAt(this, bci, oopMap); + return BitSet.valueOf(oopMap); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index ce927e03ea1..41eccc9d1c6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -28,6 +28,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.BitSet; /** * Represents a resolved Java method. Methods, like fields and types, are resolved through diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 12bad736adf..d82a7dcbc90 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -35,6 +35,10 @@ * @modules jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.internal.vm.ci/jdk.vm.ci.common + * jdk.internal.vm.ci/jdk.vm.ci.hotspot + * java.base/jdk.internal.classfile + * java.base/jdk.internal.classfile.attribute + * java.base/jdk.internal.classfile.constantpool * java.base/jdk.internal.reflect * java.base/jdk.internal.misc * java.base/jdk.internal.vm @@ -50,6 +54,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.DataInputStream; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -61,18 +66,35 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.junit.Assert; import org.junit.Test; import jdk.internal.vm.test.AnnotationTestInput; +import jdk.internal.classfile.Attributes; +import jdk.internal.classfile.Classfile; +import jdk.internal.classfile.ClassModel; +import jdk.internal.classfile.CodeElement; +import jdk.internal.classfile.MethodModel; +import jdk.internal.classfile.Instruction; +import jdk.internal.classfile.attribute.CodeAttribute; + import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -82,6 +104,7 @@ import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation2; import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.Annotation3; import jdk.vm.ci.runtime.test.TestResolvedJavaMethod.AnnotationDataTest.NumbersDE; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; /** * Tests for {@link ResolvedJavaMethod}. @@ -567,6 +590,152 @@ public void getAnnotationDataTest() throws Exception { Assert.assertTrue(numbersDEType.isInitialized()); } + private static ClassModel readClassfile(Class c) throws Exception { + String name = c.getName(); + final int lastDot = name.lastIndexOf('.'); + if (lastDot != -1) { + name = name.substring(lastDot + 1); + } + URI uri = c.getResource(name + ".class").toURI(); + if (uri.getScheme().equals("jar")) { + final String[] parts = uri.toString().split("!"); + if (parts.length == 2) { + try (FileSystem fs = FileSystems.newFileSystem(URI.create(parts[0]), new HashMap<>())) { + return Classfile.of().parse(fs.getPath(parts[1])); + } + } + } + return Classfile.of().parse(Paths.get(uri)); + } + + public static void methodWithManyArgs( + Object o0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, + int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, + int i16, int i17, int i18, int i19, int i20, int i21, int i22, int i23, + int i24, int i25, int i26, int i27, int i28, int i29, int i30, int i31, + int i32, int i33, int i34, int i35, int i36, int i37, int i38, int i39, + int i40, int i41, int i42, int i43, int i44, int i45, int i46, int i47, + int i48, int i49, int i50, int i51, int i52, int i53, int i54, int i55, + int i56, int i57, int i58, int i59, int i60, int i61, int i62, int i63, + Object o64, int i65, int i66, int i67, int i68, int i69, int i70, int i71, + int i72, int i73, int i74, int i75, int i76, int i77, int i78, int i79, + int i80, int i81, int i82, int i83, int i84, int i85, int i86, int i87, + int i88, int i89, int i90, int i91, int i92, int i93, int i94, int i95, + int i96, int i97, int i98, int i99, int i100, int i101, int i102, int i103, + int i104, int i105, int i106, int i107, int i108, int i109, int i110, int i111, + int i112, int i113, int i114, int i115, int i116, int i117, int i118, int i119, + int i120, int i121, int i122, int i123, int i124, int i125, int i126, int i127, + Object o128) + { + o0.hashCode(); + o64.hashCode(); + if (o128 != null) { + Object t1 = "tmp val"; + t1.hashCode(); + } else { + int t1 = 42 + i1; + String.valueOf(t1); + } + o128.hashCode(); + } + + private static Map buildMethodMap(ResolvedJavaType type) { + Map methodMap = new HashMap<>(); + for (ResolvedJavaMethod m : type.getDeclaredMethods()) { + if (m.hasBytecodes()) { + String key = m.getName() + ":" + m.getSignature().toMethodDescriptor(); + methodMap.put(key, m); + } + } + for (ResolvedJavaMethod m : type.getDeclaredConstructors()) { + if (m.hasBytecodes()) { + String key = ":" + m.getSignature().toMethodDescriptor(); + methodMap.put(key, m); + } + } + ResolvedJavaMethod clinit = type.getClassInitializer(); + if (clinit != null) { + String key = ":()V"; + methodMap.put(key, clinit); + } + return methodMap; + } + + @Test + public void getOopMapAtTest() throws Exception { + Collection> allClasses = new ArrayList<>(classes); + + // Add this class so that methodWithManyArgs is processed + allClasses.add(getClass()); + + boolean[] processedMethodWithManyArgs = {false}; + + for (Class c : allClasses) { + if (c.isArray() || c.isPrimitive() || c.isHidden()) { + continue; + } + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Map methodMap = buildMethodMap(type); + ClassModel cf = readClassfile(c); + for (MethodModel cm : cf.methods()) { + cm.findAttribute(Attributes.CODE).ifPresent(codeAttr -> { + String key = cm.methodName().stringValue() + ":" + cm.methodType().stringValue(); + HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) Objects.requireNonNull(methodMap.get(key)); + boolean isMethodWithManyArgs = c == getClass() && m.getName().equals("methodWithManyArgs"); + if (isMethodWithManyArgs) { + processedMethodWithManyArgs[0] = true; + } + int maxSlots = m.getMaxLocals() + m.getMaxStackSize(); + + int bci = 0; + Map expectOopMaps = !isMethodWithManyArgs ? null : Map.of( + "{0, 64, 128}", new int[] {0}, + "{0, 64, 128, 130}", new int[] {0}, + "{0, 64, 128, 129}", new int[] {0}); + for (CodeElement i : codeAttr.elementList()) { + if (i instanceof Instruction ins) { + BitSet oopMap = m.getOopMapAt(bci); + if (isMethodWithManyArgs) { + System.out.printf("methodWithManyArgs@%d [%d]: %s%n", bci, maxSlots, oopMap); + System.out.printf("methodWithManyArgs@%d [%d]: %s%n", bci, maxSlots, ins); + + // Assumes stability of javac output + String where = "methodWithManyArgs@" + bci; + String oopMapString = String.valueOf(oopMap); + int[] count = expectOopMaps.get(oopMapString); + if (count == null) { + throw new AssertionError(where + ": unexpected oop map: " + oopMapString); + } + count[0]++; + } + + // Requesting an oop map at an invalid BCI must throw an exception + if (ins.sizeInBytes() > 1) { + try { + oopMap = m.getOopMapAt(bci + 1); + throw new AssertionError("expected exception for illegal bci %d in %s: %s".formatted(bci + 1, m.format("%H.%n(%p)"), oopMap)); + } catch(IllegalArgumentException e) { + // expected + } + } + bci += ins.sizeInBytes(); + } + } + if (isMethodWithManyArgs) { + for (var e : expectOopMaps.entrySet()) { + if (e.getValue()[0] == 0) { + throw new AssertionError(m.format("%H.%n(%p)") + "did not find expected oop map: " + e.getKey()); + } + System.out.printf("methodWithManyArgs: %s = %d%n", e.getKey(), e.getValue()[0]); + } + } + }); + } + } + + Assert.assertTrue(processedMethodWithManyArgs[0]); + } + private Method findTestMethod(Method apiMethod) { String testName = apiMethod.getName() + "Test"; for (Method m : getClass().getDeclaredMethods()) { From 83b01cf3c28bc38b953d6e7e41bb7d730d91179f Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 21 Sep 2023 16:42:14 +0000 Subject: [PATCH 15/29] 8311922: [macOS] right-Option key fails to generate release event Reviewed-by: honkar, prr --- .../macosx/native/libawt_lwawt/awt/AWTEvent.m | 2 +- .../event/KeyEvent/OptionKeyEventTest.java | 184 ++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/awt/event/KeyEvent/OptionKeyEventTest.java diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m index 6e6a9fe9b6d..0f09c59c2c0 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m @@ -291,7 +291,7 @@ //kCGSFlagsMaskAppleLeftAlternateKey, //kCGSFlagsMaskAppleRightAlternateKey, 58, - 0, + 61, java_awt_event_InputEvent_ALT_DOWN_MASK, java_awt_event_InputEvent_ALT_MASK, java_awt_event_KeyEvent_VK_ALT diff --git a/test/jdk/java/awt/event/KeyEvent/OptionKeyEventTest.java b/test/jdk/java/awt/event/KeyEvent/OptionKeyEventTest.java new file mode 100644 index 00000000000..e2e42a0ca60 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/OptionKeyEventTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8311922 + * @key headful + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary To test both option key press and release event on Mac OS + * @run main/manual OptionKeyEventTest + * @requires (os.family == "mac") + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class OptionKeyEventTest extends JFrame + implements KeyListener, ActionListener { + private static JTextArea displayArea; + private static JTextField typingArea; + private static final String newline = System.getProperty("line.separator"); + private static final String INSTRUCTIONS = + "This test checks if the key events for the left and right\n" + + "option keys are correct. To complete the test, ensure the\n" + + "OptionKeyEventTest window's typing area is focused.\n" + + "Press and release the left option key. Then press and release\n" + + "the right option key. Confirm in the display area and pass the\n" + + "test if these are correct, otherwise this test fails: \n\n" + + "1. 'KEY PRESSED' appears first, followed by a 'KEY RELEASED'\n" + + "for each option button\n" + + "2. 'key location' shows 'left' or 'right' accordingly, not\n" + + "'standard' or 'unknown'"; + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException { + PassFailJFrame passFailJFrame = new PassFailJFrame("OptionKeyEventTest", + INSTRUCTIONS, 5, 15, 35); + createAndShowGUI(); + passFailJFrame.awaitAndCheck(); + } + + private static void createAndShowGUI() + throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(() -> { + OptionKeyEventTest frame = + new OptionKeyEventTest("OptionKeyEventTest"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.addComponentsToPane(); + frame.pack(); + frame.setVisible(true); + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + typingArea.requestFocus(); + }); + } + + private void addComponentsToPane() { + JButton button = new JButton("Clear"); + button.addActionListener(this); + + typingArea = new JTextField(20); + typingArea.addKeyListener(this); + + displayArea = new JTextArea(); + displayArea.setEditable(false); + displayArea.setFocusable(false); + JScrollPane scrollPane = new JScrollPane(displayArea); + scrollPane.setPreferredSize(new Dimension(375, 125)); + + getContentPane().add(typingArea, BorderLayout.PAGE_START); + getContentPane().add(scrollPane, BorderLayout.CENTER); + getContentPane().add(button, BorderLayout.PAGE_END); + } + + public OptionKeyEventTest(String name) { + super(name); + } + + public void keyTyped(KeyEvent e) { + displayInfo(e, "KEY TYPED: "); + } + + public void keyPressed(KeyEvent e) { + displayInfo(e, "KEY PRESSED: "); + } + + public void keyReleased(KeyEvent e) { + displayInfo(e, "KEY RELEASED: "); + } + + public void actionPerformed(ActionEvent e) { + //Clear the text components. + displayArea.setText(""); + typingArea.setText(""); + + typingArea.requestFocusInWindow(); + } + + private void displayInfo(KeyEvent e, String keyStatus) { + int id = e.getID(); + String keyString; + if (id == KeyEvent.KEY_TYPED) { + char c = e.getKeyChar(); + keyString = "key character = '" + c + "'"; + } else { + int keyCode = e.getKeyCode(); + keyString = "key code = " + keyCode + + " (" + + KeyEvent.getKeyText(keyCode) + + ")"; + } + + int modifiersEx = e.getModifiersEx(); + String modString = "extended modifiers = " + modifiersEx; + String tmpString = KeyEvent.getModifiersExText(modifiersEx); + if (tmpString.length() > 0) { + modString += " (" + tmpString + ")"; + } else { + modString += " (no extended modifiers)"; + } + + String actionString = "action key? "; + if (e.isActionKey()) { + actionString += "YES"; + } else { + actionString += "NO"; + } + + String locationString = "key location: "; + int location = e.getKeyLocation(); + if (location == KeyEvent.KEY_LOCATION_STANDARD) { + locationString += "standard"; + } else if (location == KeyEvent.KEY_LOCATION_LEFT) { + locationString += "left"; + } else if (location == KeyEvent.KEY_LOCATION_RIGHT) { + locationString += "right"; + } else if (location == KeyEvent.KEY_LOCATION_NUMPAD) { + locationString += "numpad"; + } else { // (location == KeyEvent.KEY_LOCATION_UNKNOWN) + locationString += "unknown"; + } + + displayArea.append(keyStatus + newline + + " " + keyString + newline + + " " + modString + newline + + " " + actionString + newline + + " " + locationString + newline); + displayArea.setCaretPosition(displayArea.getDocument().getLength()); + } +} \ No newline at end of file From 015f6f5d9497b8cef9ba2e789799a28bcd454341 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Thu, 21 Sep 2023 17:00:46 +0000 Subject: [PATCH 16/29] 8315771: [JVMCI] Resolution of bootstrap methods with int[] static arguments Reviewed-by: dnsimon, psandoz --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 14 ++- .../jdk/vm/ci/hotspot/CompilerToVM.java | 22 +++++ .../vm/ci/hotspot/HotSpotConstantPool.java | 62 ++++++++++++- .../classes/jdk/vm/ci/meta/ConstantPool.java | 27 +++++- .../ci/hotspot/test/TestDynamicConstant.java | 87 ++++++++++++++++--- 5 files changed, 194 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 5affc354ad3..b5325611835 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -771,9 +771,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR } // Get the indy entry based on CP index int indy_index = -1; - for (int i = 0; i < cp->resolved_indy_entries_length(); i++) { - if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) { - indy_index = i; + if (is_indy) { + for (int i = 0; i < cp->resolved_indy_entries_length(); i++) { + if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) { + indy_index = i; + } } } // Resolve the bootstrap specifier, its name, type, and static arguments @@ -839,6 +841,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR return JVMCIENV->get_jobjectArray(bsmi); C2V_END +C2V_VMENTRY_0(jint, bootstrapArgumentIndexAt, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint cpi, jint index)) + constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp)); + return cp->bootstrap_argument_index_at(cpi, index); +C2V_END + C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index, jint opcode)) constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp)); return cp->name_and_type_ref_index_at(index, (Bytecodes::Code)opcode); @@ -3177,6 +3184,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)}, {CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, {CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)}, + {CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)}, {CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)}, {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)}, {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)}, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 98eac1eb5bf..a70624e0aad 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -483,6 +483,28 @@ Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, int cpi) { private native Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi); + /** + * Gets the constant pool index of a static argument of a {@code CONSTANT_Dynamic_info} or + * @{code CONSTANT_InvokeDynamic_info} entry. Used when the list of static arguments in the + * {@link BootstrapMethodInvocation} is a {@code List} of the form + * {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved and that + * the JDK has to lookup the arguments when they are needed. The {@code cpi} corresponds to + * {@code pool_index} and the {@code index} has to be smaller than {@code arg_count}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a {@code CONSTANT_Dynamic_info} or a @{code CONSTANT_InvokeDynamic_info}, or if the index + * is out of bounds. + * + * @param cpi the index of a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info} entry + * @param index the index of the static argument in the list of static arguments + * @return the constant pool index associated with the static argument + */ + int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, int cpi, int index) { + return bootstrapArgumentIndexAt(constantPool, constantPool.getConstantPoolPointer(), cpi, index); + } + + private native int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi, int index); + /** * If {@code cpi} denotes an entry representing a signature polymorphic method ({@jvms 2.9}), * this method ensures that the type referenced by the entry is loaded and initialized. It diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java index 51917d3fb7f..98eb0093c09 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -27,6 +27,8 @@ import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; +import java.util.AbstractList; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -38,6 +40,7 @@ import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; @@ -504,6 +507,60 @@ private int flags() { return UNSAFE.getInt(getConstantPoolPointer() + config().constantPoolFlagsOffset); } + /** + * Represents a list of static arguments from a {@link BootstrapMethodInvocation} of the form + * {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved + * and that the JDK has to lookup the arguments when they are needed. The {@code bssIndex} + * corresponds to {@code pool_index} and the {@code size} corresponds to {@code arg_count}. + */ + static class CachedBSMArgs extends AbstractList { + private final JavaConstant[] cache; + private final HotSpotConstantPool cp; + private final int bssIndex; + + CachedBSMArgs(HotSpotConstantPool cp, int bssIndex, int size) { + this.cp = cp; + this.bssIndex = bssIndex; + this.cache = new JavaConstant[size]; + } + + /** + * Lazily resolves and caches the argument at the given index and returns it. The method + * {@link CompilerToVM#bootstrapArgumentIndexAt} is used to obtain the constant pool + * index of the entry and the method {@link ConstantPool#lookupConstant} is used to + * resolve it. If the resolution failed, the index is returned as a + * {@link PrimitiveConstant}. + * + * @param index index of the element to return + * @return A {@link JavaConstant} corresponding to the static argument requested. A return + * value of type {@link PrimitiveConstant} represents an unresolved constant pool entry + */ + @Override + public JavaConstant get(int index) { + JavaConstant res = cache[index]; + if (res == null) { + int argCpi = compilerToVM().bootstrapArgumentIndexAt(cp, bssIndex, index); + Object object = cp.lookupConstant(argCpi, false); + if (object instanceof PrimitiveConstant primitiveConstant) { + res = runtime().getReflection().boxPrimitive(primitiveConstant); + } else if (object instanceof JavaConstant javaConstant) { + res = javaConstant; + } else if (object instanceof JavaType type) { + res = runtime().getReflection().forObject(type); + } else { + res = JavaConstant.forInt(argCpi); + } + cache[index] = res; + } + return res; + } + + @Override + public int size() { + return cache.length; + } + } + static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation { private final boolean indy; private final ResolvedJavaMethod method; @@ -582,8 +639,9 @@ public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int staticArgumentsList = List.of((JavaConstant[]) staticArguments); } else { int[] bsciArgs = (int[]) staticArguments; - String message = String.format("Resolving bootstrap static arguments for %s using BootstrapCallInfo %s not supported", method.format("%H.%n(%p)"), Arrays.toString(bsciArgs)); - throw new IllegalArgumentException(message); + int argCount = bsciArgs[0]; + int bss_index = bsciArgs[1]; + staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount); } return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList); default: diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java index 5a53de47f6a..2273b256f03 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java @@ -131,7 +131,7 @@ default JavaMethod lookupMethod(int cpi, int opcode) { /** * The details for invoking a bootstrap method associated with a {@code CONSTANT_Dynamic_info} - * or {@code CONSTANT_InvokeDynamic_info} pool entry . + * or {@code CONSTANT_InvokeDynamic_info} pool entry. * * @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info} * Structures @@ -165,6 +165,29 @@ interface BootstrapMethodInvocation { /** * Gets the static arguments with which the bootstrap method will be invoked. * + * The {@linkplain JavaConstant#getJavaKind kind} of each argument will be + * {@link JavaKind#Object} or {@link JavaKind#Int}. The latter represents an + * unresolved {@code CONSTANT_Dynamic_info} entry. To resolve this entry, the + * corresponding bootstrap method has to be called first: + * + *
+         * List args = bmi.getStaticArguments();
+         * List resolvedArgs = new ArrayList<>(args.size());
+         * for (JavaConstant c : args) {
+         *     JavaConstant r = c;
+         *     if (c.getJavaKind() == JavaKind.Int) {
+         *         // If needed, access corresponding BootstrapMethodInvocation using
+         *         // cp.lookupBootstrapMethodInvocation(pc.asInt(), -1)
+         *         r = cp.lookupConstant(c.asInt(), true);
+         *     } else {
+         *         assert c.getJavaKind() == JavaKind.Object;
+         *     }
+         *     resolvedArgs.append(r);
+         * }
+         * 
+ * + * The other types of entries are already resolved an can be used directly. + * * @jvms 5.4.3.6 */ List getStaticArguments(); @@ -182,8 +205,6 @@ interface BootstrapMethodInvocation { * {@code index} was not decoded from a bytecode stream * @return the bootstrap method invocation details or {@code null} if the entry specified by {@code index} * is not a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info} - * @throws IllegalArgumentException if the bootstrap method invocation makes use of - * {@code java.lang.invoke.BootstrapCallInfo} * @jvms 4.7.23 The {@code BootstrapMethods} Attribute */ default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) { diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java index c69c4e5a345..32135e46bc1 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java @@ -32,6 +32,9 @@ * @run testng/othervm * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler * jdk.vm.ci.hotspot.test.TestDynamicConstant + * @run testng/othervm + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -XX:UseBootstrapCallInfo=3 + * jdk.vm.ci.hotspot.test.TestDynamicConstant */ package jdk.vm.ci.hotspot.test; @@ -61,6 +64,7 @@ import jdk.vm.ci.hotspot.HotSpotConstantPool; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -86,6 +90,12 @@ enum CondyType { */ CALL_DIRECT_BSM, + /** + * Condy whose bootstrap method is one of the {@code TestDynamicConstant.getBSM( constant, int i)} + * methods with one condy arg and one int arg. + */ + CALL_DIRECT_WITH_ARGS_BSM, + /** * Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the * {@code TestDynamicConstant.get()} methods. @@ -164,6 +174,24 @@ byte[] generateClassfile() { run.visitInsn(type.getOpcode(IRETURN)); run.visitMaxs(0, 0); run.visitEnd(); + } else if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) { + // Example: int TestDynamicConstant.getIntBSM(MethodHandles.Lookup l, String name, + // Class type, int constant, int i) + String sig1 = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc; + String sig2 = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;" + desc + "I)" + desc; + + Handle handle1 = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig1, false); + Handle handle2 = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig2, false); + + ConstantDynamic condy1 = new ConstantDynamic("const1", desc, handle1); + ConstantDynamic condy2 = new ConstantDynamic("const2", desc, handle2, condy1, Integer.MAX_VALUE); + + condy = condy2; + MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null); + run.visitLdcInsn(condy); + run.visitInsn(type.getOpcode(IRETURN)); + run.visitMaxs(0, 0); + run.visitEnd(); } else if (condyType == CondyType.CALL_INDIRECT_BSM) { // Example: int TestDynamicConstant.getInt() Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false); @@ -309,6 +337,12 @@ public void test() throws Throwable { assertNoEagerConstantResolution(testClass, cp, getTagAt); assertLookupBMIDoesNotInvokeBM(metaAccess, testClass); + if (type != Object.class) { + testLookupBootstrapMethodInvocation(condyType, metaAccess, testClass, getTagAt); + } else { + // StringConcatFactoryStringConcatFactory cannot accept null constants + } + Object lastConstant = null; for (int cpi = 1; cpi < cp.length(); cpi++) { String tag = String.valueOf(getTagAt.invoke(cp, cpi)); @@ -330,12 +364,6 @@ public void test() throws Throwable { actual = ((HotSpotObjectConstant) lastConstant).asObject(type); } Assert.assertEquals(actual, expect, m + ":"); - - if (type != Object.class) { - testLookupBootstrapMethodInvocation(condyType, metaAccess, testClass, getTagAt); - } else { - // StringConcatFactoryStringConcatFactory cannot accept null constants - } } } } @@ -364,10 +392,29 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess Assert.assertTrue(expectedBSMs.contains(bsm), expectedBSMs.toString()); } else { Assert.assertFalse(bsmi.isInvokeDynamic()); - if (condyType == CondyType.CALL_DIRECT_BSM) { - Assert.assertTrue(bsm.startsWith("jdk.vm.ci.hotspot.test.TestDynamicConstant.get") && bsm.endsWith("BSM"), bsm); - } else { - Assert.assertEquals(bsm, "java.lang.invoke.ConstantBootstraps.invoke"); + checkBsmName(condyType, bsm); + List staticArguments = bsmi.getStaticArguments(); + for (int i = 0; i < staticArguments.size(); ++i) { + JavaConstant constant = staticArguments.get(i); + if (constant instanceof PrimitiveConstant) { + String innerTag = String.valueOf(getTagAt.invoke(cp, constant.asInt())); + if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) { + Assert.assertEquals(i, 0); + Assert.assertEquals(innerTag, "Dynamic"); + } + if (innerTag.equals("Dynamic")) { + BootstrapMethodInvocation innerBsmi = cp.lookupBootstrapMethodInvocation(constant.asInt(), -1); + String innerBsm = innerBsmi.getMethod().format("%H.%n"); + checkBsmName(condyType, innerBsm); + } else { + Assert.assertEquals(innerTag, "MethodHandle"); + } + } else { + if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) { + Assert.assertEquals(i, 1); + } + Assert.assertTrue(staticArguments.get(i) instanceof HotSpotObjectConstant); + } } } } else { @@ -378,6 +425,14 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess testLoadReferencedType(concat, cp); } + private static void checkBsmName(CondyType condyType, String bsm) { + if (condyType == CondyType.CALL_DIRECT_BSM || condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) { + Assert.assertTrue(bsm.startsWith("jdk.vm.ci.hotspot.test.TestDynamicConstant.get") && bsm.endsWith("BSM"), bsm); + } else { + Assert.assertEquals(bsm, "java.lang.invoke.ConstantBootstraps.invoke"); + } + } + private static int beS4(byte[] data, int bci) { return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff); } @@ -425,6 +480,18 @@ private static void testLoadReferencedType(ResolvedJavaMethod method, ConstantPo @SuppressWarnings("unused") public static Object getObjectBSM (MethodHandles.Lookup l, String name, Class type) { return null; } @SuppressWarnings("unused") public static List getListBSM (MethodHandles.Lookup l, String name, Class type) { return List.of("element"); } + @SuppressWarnings("unused") public static boolean getBooleanBSM(MethodHandles.Lookup l, String name, Class type, boolean constant, int i) { return true; } + @SuppressWarnings("unused") public static char getCharBSM (MethodHandles.Lookup l, String name, Class type, char constant, int i) { return '*'; } + @SuppressWarnings("unused") public static short getShortBSM (MethodHandles.Lookup l, String name, Class type, short constant, int i) { return Short.MAX_VALUE; } + @SuppressWarnings("unused") public static byte getByteBSM (MethodHandles.Lookup l, String name, Class type, byte constant, int i) { return Byte.MAX_VALUE; } + @SuppressWarnings("unused") public static int getIntBSM (MethodHandles.Lookup l, String name, Class type, int constant, int i) { return Integer.MAX_VALUE; } + @SuppressWarnings("unused") public static float getFloatBSM (MethodHandles.Lookup l, String name, Class type, float constant, int i) { return Float.MAX_VALUE; } + @SuppressWarnings("unused") public static long getLongBSM (MethodHandles.Lookup l, String name, Class type, long constant, int i) { return Long.MAX_VALUE; } + @SuppressWarnings("unused") public static double getDoubleBSM (MethodHandles.Lookup l, String name, Class type, double constant, int i) { return Double.MAX_VALUE; } + @SuppressWarnings("unused") public static String getStringBSM (MethodHandles.Lookup l, String name, Class type, String constant, int i) { return "a string"; } + @SuppressWarnings("unused") public static Object getObjectBSM (MethodHandles.Lookup l, String name, Class type, Object constant, int i) { return null; } + @SuppressWarnings("unused") public static List getListBSM (MethodHandles.Lookup l, String name, Class type, List constant, int i) { return List.of("element"); } + public static boolean getBoolean() { return true; } public static char getChar () { return '*'; } From c698b45a7bcb0eedeed979d482f8ab15cf16baaa Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Thu, 21 Sep 2023 17:31:46 +0000 Subject: [PATCH 17/29] 8313229: DHEKeySizing.java should be modified to use TLS versions TLSv1, TLSv1.1, TLSv1.2 Reviewed-by: jnimeh --- .../ssl/DHKeyExchange/DHEKeySizing.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java b/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java index c6c8841f6c7..e52fb76c4ab 100644 --- a/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java +++ b/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java @@ -32,58 +32,55 @@ * @summary make ephemeral DH key match the length of the certificate key * @library /javax/net/ssl/templates * @run main/othervm -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1643 267 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA 1643 267 TLSv1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 1259 75 TLSv1.1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=matched * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 1259 75 TLSv1.2 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=legacy * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 1259 75 TLSv1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=1024 * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 - * + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 1259 75 TLSv1.1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 233 75 - * + * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA 233 75 TLSv1.2 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1643 267 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA 1643 267 TLSv1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=legacy * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1323 107 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA 1323 107 TLSv1.1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=matched * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1643 267 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA 1645 267 TLSv1.2 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.ephemeralDHKeySize=1024 * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1387 139 - * + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA 1387 139 TLSv1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 617 267 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 617 267 TLSv1.1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false * -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 297 107 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 297 107 TLSv1.2 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false * -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 617 267 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 617 267 TLSv1 * @run main/othervm -Djsse.enableFFDHE=false * -Djdk.tls.client.enableSessionTicketExtension=false * -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 361 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 361 139 TLSv1.1 */ /* @@ -133,11 +130,13 @@ public class DHEKeySizing extends SSLEngineTemplate { // key length bias because of the stripping of leading zero bytes of // negotiated DH keys. // - // This is an effort to mimum intermittent failure when we cannot + // This is an effort to minimize intermittent failures when we cannot // estimate what's the exact number of leading zero bytes of // negotiated DH keys. private final static int KEY_LEN_BIAS = 6; + private static String protocol; + private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut, SSLEngineResult result, Status status, HandshakeStatus hsStatus, @@ -175,8 +174,8 @@ private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut, } } - private void test(String cipherSuite, boolean exportable, - int lenServerKeyEx, int lenClientKeyEx) throws Exception { + private void test(String cipherSuite, int lenServerKeyEx, + int lenClientKeyEx) throws Exception { SSLEngineResult result1; // clientEngine's results from last operation SSLEngineResult result2; // serverEngine's results from last operation @@ -316,15 +315,16 @@ public static void main(String args[]) throws Exception { if (args.length != 4) { System.out.println( "Usage: java DHEKeySizing cipher-suite " + - "exportable(true|false)\n" + - " size-of-server-hello-record size-of-client-key-exchange"); + "size-of-server-hello-record\n" + + " size-of-client-key-exchange protocol"); throw new Exception("Incorrect usage!"); } + protocol = args[3]; + (new DHEKeySizing()).test(args[0], - Boolean.parseBoolean(args[1]), - Integer.parseInt(args[2]), - Integer.parseInt(args[3])); + Integer.parseInt(args[1]), + Integer.parseInt(args[2])); System.out.println("Test Passed."); } @@ -359,12 +359,12 @@ protected SSLContext createClientSSLContext() throws Exception { @Override protected ContextParameters getClientContextParameters() { - return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); + return new ContextParameters(protocol, "PKIX", "NewSunX509"); } @Override protected ContextParameters getServerContextParameters() { - return new ContextParameters("TLSv1", "PKIX", "NewSunX509"); + return new ContextParameters(protocol, "PKIX", "NewSunX509"); } private static void log(String str) { From 3b397c8552d7fd1b1084fbbc06384f3f34481ba4 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 21 Sep 2023 18:28:19 +0000 Subject: [PATCH 18/29] 8315965: Open source various AWT applet tests Reviewed-by: honkar, psadhukhan --- .../java/awt/ScrollPane/ScrollPaneTest.java | 216 ++++++++++++++++++ test/jdk/java/awt/TextArea/Length.java | 61 +++++ test/jdk/java/awt/Window/WindowOwner.java | 155 +++++++++++++ .../jdk/java/awt/font/Rotate/RotateTest3.java | 114 +++++++++ 4 files changed, 546 insertions(+) create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneTest.java create mode 100644 test/jdk/java/awt/TextArea/Length.java create mode 100644 test/jdk/java/awt/Window/WindowOwner.java create mode 100644 test/jdk/java/awt/font/Rotate/RotateTest3.java diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java b/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java new file mode 100644 index 00000000000..7b628d900a5 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +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.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.ScrollPane; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +/* + * @test + * @bug 4124460 + * @key headful + * @summary Test for initializing a Motif peer component causes a crash. +*/ + +public class ScrollPaneTest { + private static volatile Point p1 = null; + private static volatile Point p2 = null; + private static Robot robot = null; + + private static Point getClickPoint(Component component) { + Point locationOnScreen = component.getLocationOnScreen(); + Dimension size = component.getSize(); + locationOnScreen.x += size.width / 2; + locationOnScreen.y += size.height / 2; + return locationOnScreen; + } + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + + try { + doTest(); + } finally { + ScrollPaneTester.disposeAll(); + } + } + + private static void doTest() throws Exception { + EventQueue.invokeAndWait(ScrollPaneTester::initAndShowGui); + + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p1 = getClickPoint(ScrollPaneTester.st1.buttonRight); + p2 = getClickPoint(ScrollPaneTester.st1.buttonSwap); + }); + + robot.mouseMove(p1.x, p1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.mouseMove(p2.x, p2.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p1 = getClickPoint(ScrollPaneTester.st2.buttonRight); + p2 = getClickPoint(ScrollPaneTester.st2.buttonSwap); + }); + + robot.mouseMove(p1.x, p1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.mouseMove(p2.x, p2.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } +} + +class ScrollPaneTester implements ActionListener { + static ScrollPaneTester st1, st2; + final Button buttonLeft, buttonRight, buttonQuit, buttonSwap; + protected ScrollPane sp; + protected Frame f; + + public static void initAndShowGui() { + ScrollPaneTester.st1 = new ScrollPaneTester(true); + ScrollPaneTester.st2 = new ScrollPaneTester(false); + } + + public ScrollPaneTester(boolean large) { + sp = new ScrollPane(ScrollPane.SCROLLBARS_NEVER); + + Panel p = new Panel(); + + if (large) { + p.setLayout(new GridLayout(10, 10)); + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) { + TextField tf = new TextField("I am " + i + j); + tf.setSize(100, 20); + p.add(tf); + } + } else { + TextField tf = new TextField("Smallness:"); + tf.setSize(150, 50); + p.add(tf); + } + + sp.add(p); + + // Button panel + buttonLeft = new Button("Left"); + buttonLeft.addActionListener(this); + buttonQuit = new Button("Quit"); + buttonQuit.addActionListener(this); + buttonSwap = new Button("Swap"); + buttonSwap.addActionListener(this); + buttonRight = new Button("Right"); + buttonRight.addActionListener(this); + + Panel bp = new Panel(); + bp.add(buttonLeft); + bp.add(buttonSwap); + bp.add(buttonQuit); + bp.add(buttonRight); + + // Window w/ button panel and scrollpane + f = new Frame("ScrollPane Test " + (large ? "large" : "small")); + f.setLayout(new BorderLayout()); + f.add("South", bp); + f.add("Center", sp); + + if (large) { + f.setSize(300, 200); + f.setLocation(100, 100); + } else { + f.setSize(200, 100); + f.setLocation(500, 100); + } + + f.setVisible(true); + } + + public static void disposeAll() { + ScrollPaneTester.st1.f.dispose(); + ScrollPaneTester.st2.f.dispose(); + } + + public static void + swapPanels() { + ScrollPane sss = st1.sp; + + st1.f.add("Center", st2.sp); + st1.sp = st2.sp; + + st2.f.add("Center", sss); + st2.sp = sss; + } + + public void + actionPerformed(ActionEvent ev) { + Object s = ev.getSource(); + + if (s == buttonLeft) { + scroll(true); + } else if (s == buttonRight) { + scroll(false); + } else if (s == buttonSwap) { + swapPanels(); + } else if (s == buttonQuit) { + disposeAll(); + } + } + + private void + scroll(boolean scroll_left) { + Point p = sp.getScrollPosition(); + + if (scroll_left) + p.x = Math.max(0, p.x - 20); + else { + int cwidth = sp.getComponent(0).getSize().width; + p.x = Math.min(p.x + 20, cwidth); + } + + sp.setScrollPosition(p); + } +} diff --git a/test/jdk/java/awt/TextArea/Length.java b/test/jdk/java/awt/TextArea/Length.java new file mode 100644 index 00000000000..1ea99659383 --- /dev/null +++ b/test/jdk/java/awt/TextArea/Length.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.awt.TextArea; + +/* + * @test + * @bug 4120876 + * @key headful + * @summary Ensure that getText can handle strings of various lengths, + * in particular strings longer than 255 characters + */ + +public class Length { + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(() -> { + TextArea ta = new TextArea(); + StringBuffer sb = new StringBuffer("x"); + + for (int i = 0; i < 14; i++) { + String s = sb.toString(); + check(ta, s.substring(1)); + check(ta, s); + check(ta, s + "y"); + sb.append(s); + } + }); + } + + static void check(TextArea ta, String s) { + ta.setText(s); + String s2 = ta.getText(); + System.err.println(s.length() + " " + s2.length()); + if (s.length() != s2.length()) { + throw new RuntimeException("Expected " + s.length() + + "chars, got " + s2.length()); + } + } +} diff --git a/test/jdk/java/awt/Window/WindowOwner.java b/test/jdk/java/awt/Window/WindowOwner.java new file mode 100644 index 00000000000..82cb35a1faa --- /dev/null +++ b/test/jdk/java/awt/Window/WindowOwner.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Window; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @key headful + * @summary automated test for window-ownership on Windows, Frames, and Dialogs + */ + +public class WindowOwner extends Panel { + + Label status = null; + static List windowsToDispose = new ArrayList<>(); + + public static void main(String[] args) throws Exception { + WindowOwner windowOwner = new WindowOwner(); + try { + EventQueue.invokeAndWait(windowOwner::init); + Thread.sleep(2000); + } finally { + EventQueue.invokeAndWait( + () -> windowsToDispose.forEach(Window::dispose) + ); + } + } + + public void init() { + status = new Label(); + add(status); + + statusMessage("Testing Window Ownership..."); + + // Test Frame as owner + Frame frame0 = new Frame("WindowOwner Test"); + windowsToDispose.add(frame0); + frame0.add("Center", new Label("Frame Level0")); + + Dialog dialog1 = new Dialog(frame0, "WindowOwner Test"); + windowsToDispose.add(dialog1); + dialog1.add("Center", new Label("Dialog Level1")); + verifyOwner(dialog1, frame0); + + Window window1 = new Window(frame0); + windowsToDispose.add(window1); + window1.add("Center", new Label("Window Level1")); + window1.setBounds(10, 10, 140, 70); + verifyOwner(window1, frame0); + + verifyOwnee(frame0, dialog1); + verifyOwnee(frame0, window1); + + // Test Dialog as owner + Dialog dialog2 = new Dialog(dialog1, "WindowOwner Test"); + windowsToDispose.add(dialog2); + dialog2.add("Center", new Label("Dialog Level2")); + verifyOwner(dialog2, dialog1); + + Window window2 = new Window(dialog1); + windowsToDispose.add(window2); + window2.add("Center", new Label("Window Level2")); + window2.setBounds(110, 110, 140, 70); + verifyOwner(window2, dialog1); + + verifyOwnee(dialog1, window2); + verifyOwnee(dialog1, dialog2); + + // Test Window as owner + Window window3 = new Window(window2); + windowsToDispose.add(window3); + window3.add("Center", new Label("Window Level3")); + window3.setBounds(210, 210, 140, 70); + verifyOwner(window3, window2); + verifyOwnee(window2, window3); + + // Ensure native peers handle ownership without errors + frame0.pack(); + frame0.setVisible(true); + + dialog1.pack(); + dialog1.setVisible(true); + + window1.setLocation(50, 50); + window1.setVisible(true); + + dialog2.pack(); + dialog2.setVisible(true); + + window2.setLocation(100, 100); + window2.setVisible(true); + + window3.setLocation(150, 150); + window3.setVisible(true); + + statusMessage("Window Ownership test completed successfully."); + } + + public void statusMessage(String msg) { + status.setText(msg); + status.invalidate(); + validate(); + } + + public static void verifyOwner(Window ownee, Window owner) { + if (ownee.getOwner() != owner) { + throw new RuntimeException("Window owner not valid for " + + ownee.getName()); + } + } + + public static void verifyOwnee(Window owner, Window ownee) { + Window[] ownedWins = owner.getOwnedWindows(); + if (!windowInList(ownedWins, ownee)) { + throw new RuntimeException("Ownee " + ownee.getName() + + " not found in owner list for " + owner.getName()); + } + } + + public static boolean windowInList(Window[] windows, Window target) { + for (Window window : windows) { + if (window == target) { + return true; + } + } + return false; + } +} diff --git a/test/jdk/java/awt/font/Rotate/RotateTest3.java b/test/jdk/java/awt/font/Rotate/RotateTest3.java new file mode 100644 index 00000000000..0241e65e1eb --- /dev/null +++ b/test/jdk/java/awt/font/Rotate/RotateTest3.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @key headful + * @bug 4240228 + * @summary This test is designed to test for a crashing bug in the zh + * locale on Solaris. Rotated text should be displayed, but + * anything other than a crash passes the specific test. + * For example, the missing glyph empty box may be displayed + * in some locales, or no text at all. + */ + +public class RotateTest3 extends Panel { + static JFrame frame; + + protected Java2DView java2DView; + + public RotateTest3(){ + this.setLayout(new GridLayout(1, 1)); + this.setSize(300, 300); + this.java2DView = new Java2DView(); + this.add(this.java2DView); + } + + public static void main(String[] s) throws Exception { + try { + SwingUtilities.invokeAndWait(RotateTest3::initAndShowGui); + Thread.sleep(1000); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void initAndShowGui() { + RotateTest3 panel = new RotateTest3(); + + frame = new JFrame("RotateTest3"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + frame.getContentPane().setLayout(new GridLayout(1, 1)); + frame.getContentPane().add("Center", panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static public class Java2DView extends Component { + + public void paint(Graphics g){ + Graphics2D g2d = (Graphics2D) g; + Dimension d = this.getSize(); + g.setColor(this.getBackground()); + g.fillRect(0, 0, d.width, d.height); + g2d.setPaint(Color.black); + + g2d.translate(150,150); + g2d.rotate(-Math.PI / 3); + + String testString = + "\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341"; + g2d.drawString(testString, 0, 0); + } + + public Dimension getMinimumSize(){ + return new Dimension(300, 300); + } + + public Dimension getPreferredSize(){ + return new Dimension(300, 300); + } + } +} From 4e5717754ab3009c75869bf9f228820adb86dd98 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Thu, 21 Sep 2023 19:17:24 +0000 Subject: [PATCH 19/29] 8316383: NullPointerException in AbstractSAXParser after JDK-8306632 Reviewed-by: lancea, naoto --- .../xerces/internal/parsers/SAXParser.java | 37 +++++++++++++------ .../share/classes/jdk/xml/internal/Utils.java | 27 ++++++++++++++ .../xml/jaxp/unittest/sax/XMLReaderTest.java | 17 ++++++++- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/SAXParser.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/SAXParser.java index 8213634e457..e8fd5424265 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/SAXParser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/SAXParser.java @@ -27,7 +27,9 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; import jdk.xml.internal.JdkConstants; import jdk.xml.internal.JdkProperty; +import jdk.xml.internal.Utils; import jdk.xml.internal.XMLSecurityManager; +import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -39,7 +41,7 @@ * @author Arnaud Le Hors, IBM * @author Andy Clark, IBM * - * @LastModified: July 2023 + * @LastModified: Sep 2023 */ public class SAXParser extends AbstractSAXParser { @@ -89,6 +91,7 @@ public class SAXParser */ public SAXParser(XMLParserConfiguration config) { super(config); + initSecurityManager(); } // (XMLParserConfiguration) /** @@ -125,6 +128,7 @@ public SAXParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) { fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool); } + initSecurityManager(); } // (SymbolTable,XMLGrammarPool) /** @@ -152,16 +156,6 @@ public void setProperty(String name, Object value) return; } - if (securityManager == null) { - securityManager = new XMLSecurityManager(true); - super.setProperty(Constants.SECURITY_MANAGER, securityManager); - } - - if (securityPropertyManager == null) { - securityPropertyManager = new XMLSecurityPropertyManager(); - super.setProperty(JdkConstants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager); - } - int index = securityPropertyManager.getIndex(name); if (index > -1) { /** @@ -178,4 +172,25 @@ public void setProperty(String name, Object value) } } } + + /** + * Initiates the SecurityManager. This becomes necessary when the SAXParser + * is constructed directly by, for example, XMLReaderFactory rather than + * through SAXParserFactory. + */ + private void initSecurityManager() { + try { + if (securityManager == null) { + securityManager = new XMLSecurityManager(true); + super.setProperty(Constants.SECURITY_MANAGER, securityManager); + } + + if (securityPropertyManager == null) { + securityPropertyManager = new XMLSecurityPropertyManager(); + super.setProperty(JdkConstants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager); + } + } catch (SAXException e) { + Utils.dPrint(() -> e.getMessage()); + } + } } // class SAXParser diff --git a/src/java.xml/share/classes/jdk/xml/internal/Utils.java b/src/java.xml/share/classes/jdk/xml/internal/Utils.java index 439930be15d..e60bc8f060d 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/Utils.java +++ b/src/java.xml/share/classes/jdk/xml/internal/Utils.java @@ -26,11 +26,38 @@ package jdk.xml.internal; import java.util.Arrays; +import java.util.function.Supplier; /** * General utility. Use JdkXmlUtils for XML processing related functions. */ public class Utils { + // The debug flag + private static boolean debug = false; + + /* + * The {@systemProperty jaxp.debug} property is supported by JAXP factories + * and used to print out information related to the configuration of factories + * and processors + */ + static { + try { + String val = SecuritySupport.getSystemProperty("jaxp.debug"); + // Allow simply setting the prop to turn on debug + debug = val != null && !"false".equals(val); + } + catch (SecurityException se) { + debug = false; + } + } + + // print out debug information if jaxp.debug is enabled + public static void dPrint(Supplier msgGen) { + if (debug) { + System.err.println("JAXP: " + msgGen.get()); + } + } + /** * Creates a new array with copies of the original array and additional items * appended to the end of it. diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java index 79c3bba3362..a7e508d69ef 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,11 +33,13 @@ import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderAdapter; +import org.xml.sax.helpers.XMLReaderFactory; /* * @test - * @bug 8158246 + * @bug 8158246 8316383 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow sax.XMLReaderTest * @run testng/othervm sax.XMLReaderTest @@ -69,4 +71,15 @@ public void testcreateXMLReader() throws SAXException, ParserConfigurationExcept setSystemProperty(SAX_PROPNAME, className + "nosuch"); XMLReaderAdapter adapter = new XMLReaderAdapter(); } + + /* + * @bug 8316383 + * Verifies that the XMLReader is initialized properly when it's created + * with XMLReaderFactory. + */ + @Test + public void testCreateXMLReaderWithXMLReaderFactory() throws SAXException, ParserConfigurationException { + XMLReader reader = XMLReaderFactory.createXMLReader(); + reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } } From d3e821838668a0ccc0ccd098336230975e27fd7c Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 21 Sep 2023 19:37:47 +0000 Subject: [PATCH 20/29] 8316306: Open source and convert manual Swing test Reviewed-by: honkar, azvegint --- test/jdk/javax/swing/JToolBar/bug4203039.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 test/jdk/javax/swing/JToolBar/bug4203039.java diff --git a/test/jdk/javax/swing/JToolBar/bug4203039.java b/test/jdk/javax/swing/JToolBar/bug4203039.java new file mode 100644 index 00000000000..af8b1f122c0 --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/bug4203039.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4203039 + * @summary JToolBar needs a way to limit docking to a particular orientation + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4203039 + */ + +public class bug4203039 { + private static final String instructionsText = """ + This test is used to verify that application-installed + components prevent the toolbar from docking in + those locations. + + This test has installed components on the SOUTH + and EAST, so verify the toolbar cannot dock in those + locations but can dock on the NORTH and WEST"""; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("bug4203039 Instructions") + .instructions(instructionsText) + .testTimeOut(5) + .rows(10) + .columns(35) + .build(); + + SwingUtilities.invokeAndWait(() -> { + JFrame frame = new JFrame("bug4203039"); + frame.setSize(300, 200); + + JToolBar toolbar = new JToolBar(); + JLabel label = new JLabel("This is the toolbar"); + toolbar.add(label); + + frame.add(toolbar, BorderLayout.NORTH); + + frame.add(new JComponent(){}, BorderLayout.SOUTH); + frame.add(new JComponent(){}, BorderLayout.EAST); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} From 1100dbc6b2a1f2d5c431c6f5c6eb0b9092aee817 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 21 Sep 2023 20:59:30 +0000 Subject: [PATCH 21/29] 8316695: ProblemList serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java Reviewed-by: ccheung, kbarrett --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 4d53879d642..218ee5a164c 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -133,6 +133,7 @@ serviceability/sa/TestJmapCoreMetaspace.java 8267433 macosx-x64 serviceability/sa/ClhsdbDumpclass.java 8316342 generic-all serviceability/attach/ConcAttachTest.java 8290043 linux-all +serviceability/jvmti/RedefineClasses/RedefineLeakThrowable.java 8316658 generic-all ############################################################################# From 496264c1f98d313f3df19f919b54c98fc03d88f7 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 21 Sep 2023 21:31:07 +0000 Subject: [PATCH 22/29] 8316435: sun.util.calendar.CalendarSystem subclassing should be restricted Reviewed-by: naoto --- .../sun/util/calendar/AbstractCalendar.java | 11 +++- .../sun/util/calendar/BaseCalendar.java | 15 ++++- .../sun/util/calendar/CalendarDate.java | 6 +- .../sun/util/calendar/CalendarSystem.java | 2 +- .../sun/util/calendar/CalendarUtils.java | 31 +++++----- .../classes/sun/util/calendar/Gregorian.java | 19 ++++-- .../util/calendar/ImmutableGregorianDate.java | 60 ++++++++++++++++--- .../sun/util/calendar/JulianCalendar.java | 37 ++++++++---- .../util/calendar/LocalGregorianCalendar.java | 9 +-- 9 files changed, 142 insertions(+), 48 deletions(-) diff --git a/src/java.base/share/classes/sun/util/calendar/AbstractCalendar.java b/src/java.base/share/classes/sun/util/calendar/AbstractCalendar.java index 50c8be6e314..f2582b80e47 100644 --- a/src/java.base/share/classes/sun/util/calendar/AbstractCalendar.java +++ b/src/java.base/share/classes/sun/util/calendar/AbstractCalendar.java @@ -44,7 +44,8 @@ * @since 1.5 */ -public abstract class AbstractCalendar extends CalendarSystem { +public sealed abstract class AbstractCalendar extends CalendarSystem + permits BaseCalendar { // The constants assume no leap seconds support. static final int SECOND_IN_MILLIS = 1000; @@ -60,6 +61,7 @@ public abstract class AbstractCalendar extends CalendarSystem { protected AbstractCalendar() { } + @Override public Era getEra(String eraName) { if (eras != null) { for (Era era : eras) { @@ -71,6 +73,7 @@ public Era getEra(String eraName) { return null; } + @Override public Era[] getEras() { Era[] e = null; if (eras != null) { @@ -84,19 +87,23 @@ protected void setEras(Era[] eras) { this.eras = eras; } + @Override public CalendarDate getCalendarDate() { return getCalendarDate(System.currentTimeMillis(), newCalendarDate()); } + @Override public CalendarDate getCalendarDate(long millis) { return getCalendarDate(millis, newCalendarDate()); } + @Override public CalendarDate getCalendarDate(long millis, TimeZone zone) { CalendarDate date = newCalendarDate(zone); return getCalendarDate(millis, date); } + @Override public CalendarDate getCalendarDate(long millis, CalendarDate date) { int ms = 0; // time of day int zoneOffset = 0; @@ -156,6 +163,7 @@ public CalendarDate getCalendarDate(long millis, CalendarDate date) { return date; } + @Override public long getTime(CalendarDate date) { long gd = getFixedDate(date); long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date); @@ -232,6 +240,7 @@ public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) { protected abstract boolean isLeapYear(CalendarDate date); + @Override public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) { CalendarDate ndate = (CalendarDate) date.clone(); normalize(ndate); diff --git a/src/java.base/share/classes/sun/util/calendar/BaseCalendar.java b/src/java.base/share/classes/sun/util/calendar/BaseCalendar.java index efe1b85fc21..9749ab31afd 100644 --- a/src/java.base/share/classes/sun/util/calendar/BaseCalendar.java +++ b/src/java.base/share/classes/sun/util/calendar/BaseCalendar.java @@ -36,7 +36,8 @@ * @since 1.5 */ -public abstract class BaseCalendar extends AbstractCalendar { +public sealed abstract class BaseCalendar extends AbstractCalendar + permits Gregorian, JulianCalendar, LocalGregorianCalendar { public static final int JANUARY = 1; public static final int FEBRUARY = 2; @@ -140,7 +141,8 @@ public abstract class BaseCalendar extends AbstractCalendar { 744365, // 2039 }; - public abstract static class Date extends CalendarDate { + public sealed abstract static class Date extends CalendarDate + permits Gregorian.Date, ImmutableGregorianDate, JulianCalendar.Date, LocalGregorianCalendar.Date { protected Date() { super(); } @@ -188,6 +190,7 @@ protected void setCache(int year, long jan1, int len) { } } + @Override public boolean validate(CalendarDate date) { Date bdate = (Date) date; if (bdate.isNormalized()) { @@ -214,6 +217,7 @@ public boolean validate(CalendarDate date) { return true; } + @Override public boolean normalize(CalendarDate date) { if (date.isNormalized()) { return true; @@ -303,6 +307,7 @@ void normalizeMonth(CalendarDate date) { * @throws ClassCastException if the specified date is not a * {@link BaseCalendar.Date} */ + @Override public int getYearLength(CalendarDate date) { return isLeapYear(((Date)date).getNormalizedYear()) ? 366 : 365; } @@ -318,6 +323,7 @@ public int getYearLength(CalendarDate date) { // 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1 = { -30, 0, 31, 59+1, 90+1,120+1,151+1,181+1,212+1,243+1, 273+1, 304+1, 334+1}; + @Override public int getMonthLength(CalendarDate date) { Date gdate = (Date) date; int month = gdate.getMonth(); @@ -349,6 +355,7 @@ final long getDayOfYear(int year, int month, int dayOfMonth) { } // protected + @Override public long getFixedDate(CalendarDate date) { if (!date.isNormalized()) { normalizeMonth(date); @@ -415,6 +422,7 @@ public long getFixedDate(int year, int month, int dayOfMonth, BaseCalendar.Date * {@code CalendarDate}. */ // should be 'protected' + @Override public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) { Date gdate = (Date) date; @@ -473,7 +481,7 @@ public int getDayOfWeek(CalendarDate date) { return getDayOfWeekFromFixedDate(fixedDate); } - public static final int getDayOfWeekFromFixedDate(long fixedDate) { + public static int getDayOfWeekFromFixedDate(long fixedDate) { // The fixed day 1 (January 1, 1 Gregorian) is Monday. if (fixedDate >= 0) { return (int)(fixedDate % 7) + SUNDAY; @@ -525,6 +533,7 @@ final int getGregorianYearFromFixedDate(long fixedDate) { * false otherwise. * @see CalendarUtils#isGregorianLeapYear */ + @Override protected boolean isLeapYear(CalendarDate date) { return isLeapYear(((Date)date).getNormalizedYear()); } diff --git a/src/java.base/share/classes/sun/util/calendar/CalendarDate.java b/src/java.base/share/classes/sun/util/calendar/CalendarDate.java index 528baa9e317..7485a9fb37a 100644 --- a/src/java.base/share/classes/sun/util/calendar/CalendarDate.java +++ b/src/java.base/share/classes/sun/util/calendar/CalendarDate.java @@ -59,7 +59,8 @@ * @author Masayoshi Okutsu * @since 1.5 */ -public abstract class CalendarDate implements Cloneable { +public sealed abstract class CalendarDate implements Cloneable + permits BaseCalendar.Date { public static final int FIELD_UNDEFINED = Integer.MIN_VALUE; public static final long TIME_UNDEFINED = Long.MIN_VALUE; @@ -340,6 +341,7 @@ public boolean equals(Object obj) { && zoneOffset == that.zoneOffset); } + @Override public int hashCode() { // a pseudo (local standard) time stamp value in milliseconds // from the Epoch, assuming Gregorian calendar fields. @@ -362,6 +364,7 @@ public int hashCode() { * * @return a copy of this CalendarDate */ + @Override public Object clone() { try { return super.clone(); @@ -380,6 +383,7 @@ public Object clone() { * * @see java.text.SimpleDateFormat */ + @Override public String toString() { StringBuilder sb = new StringBuilder(); CalendarUtils.sprintf0d(sb, year, 4).append('-'); diff --git a/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java b/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java index 885150fc0a4..ea4f76c5bf0 100644 --- a/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java +++ b/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java @@ -65,7 +65,7 @@ * @since 1.5 */ -public abstract class CalendarSystem { +public sealed abstract class CalendarSystem permits AbstractCalendar { /////////////////////// Calendar Factory Methods ///////////////////////// diff --git a/src/java.base/share/classes/sun/util/calendar/CalendarUtils.java b/src/java.base/share/classes/sun/util/calendar/CalendarUtils.java index 5723ebcbee0..60c2decc48b 100644 --- a/src/java.base/share/classes/sun/util/calendar/CalendarUtils.java +++ b/src/java.base/share/classes/sun/util/calendar/CalendarUtils.java @@ -25,7 +25,10 @@ package sun.util.calendar; -public class CalendarUtils { +public final class CalendarUtils { + + // Utility class should not be instantiated + private CalendarUtils() {} /** * Returns whether the specified year is a leap year in the Gregorian @@ -36,9 +39,9 @@ public class CalendarUtils { * calendar system. * @see CalendarDate#isLeapYear */ - public static final boolean isGregorianLeapYear(int gregorianYear) { - return (((gregorianYear % 4) == 0) - && (((gregorianYear % 100) != 0) || ((gregorianYear % 400) == 0))); + public static boolean isGregorianLeapYear(int gregorianYear) { + return (((gregorianYear % 4) == 0) && (((gregorianYear % 100) != 0) + || ((gregorianYear % 400) == 0))); } /** @@ -51,7 +54,7 @@ public static final boolean isGregorianLeapYear(int gregorianYear) { * calendar system. * @see CalendarDate#isLeapYear */ - public static final boolean isJulianLeapYear(int normalizedJulianYear) { + public static boolean isJulianLeapYear(int normalizedJulianYear) { return (normalizedJulianYear % 4) == 0; } @@ -64,7 +67,7 @@ public static final boolean isJulianLeapYear(int normalizedJulianYear) { * @param d a divisor that must be greater than 0 * @return the floor of the quotient */ - public static final long floorDivide(long n, long d) { + public static long floorDivide(long n, long d) { return ((n >= 0) ? (n / d) : (((n + 1L) / d) - 1L)); } @@ -78,7 +81,7 @@ public static final long floorDivide(long n, long d) { * @param d a divisor that must be greater than 0 * @return the floor of the quotient */ - public static final int floorDivide(int n, int d) { + public static int floorDivide(int n, int d) { return ((n >= 0) ? (n / d) : (((n + 1) / d) - 1)); } @@ -96,7 +99,7 @@ public static final int floorDivide(int n, int d) { * mod(n, d) is returned. * @return the floor of the quotient. */ - public static final int floorDivide(int n, int d, int[] r) { + public static int floorDivide(int n, int d, int[] r) { if (n >= 0) { r[0] = n % d; return n / d; @@ -106,20 +109,20 @@ public static final int floorDivide(int n, int d, int[] r) { return q; } - public static final long mod(long x, long y) { + public static long mod(long x, long y) { return (x - y * floorDivide(x, y)); } - public static final int mod(int x, int y) { + public static int mod(int x, int y) { return (x - y * floorDivide(x, y)); } - public static final int amod(int x, int y) { + public static int amod(int x, int y) { int z = mod(x, y); return (z == 0) ? y : z; } - public static final long amod(long x, long y) { + public static long amod(long x, long y) { long z = mod(x, y); return (z == 0) ? y : z; } @@ -127,7 +130,7 @@ public static final long amod(long x, long y) { /** * Mimics sprintf(buf, "%0*d", decaimal, width). */ - public static final StringBuilder sprintf0d(StringBuilder sb, int value, int width) { + public static StringBuilder sprintf0d(StringBuilder sb, int value, int width) { long d = value; if (d < 0) { sb.append('-'); @@ -146,7 +149,7 @@ public static final StringBuilder sprintf0d(StringBuilder sb, int value, int wid return sb; } - public static final StringBuffer sprintf0d(StringBuffer sb, int value, int width) { + public static StringBuffer sprintf0d(StringBuffer sb, int value, int width) { long d = value; if (d < 0) { sb.append('-'); diff --git a/src/java.base/share/classes/sun/util/calendar/Gregorian.java b/src/java.base/share/classes/sun/util/calendar/Gregorian.java index d100687e4f5..c983814cecd 100644 --- a/src/java.base/share/classes/sun/util/calendar/Gregorian.java +++ b/src/java.base/share/classes/sun/util/calendar/Gregorian.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,21 +34,23 @@ * @since 1.5 */ -public class Gregorian extends BaseCalendar { +public final class Gregorian extends BaseCalendar { - static class Date extends BaseCalendar.Date { - protected Date() { + static final class Date extends BaseCalendar.Date { + Date() { super(); } - protected Date(TimeZone zone) { + Date(TimeZone zone) { super(zone); } + @Override public int getNormalizedYear() { return getYear(); } + @Override public void setNormalizedYear(int normalizedYear) { setYear(normalizedYear); } @@ -57,30 +59,37 @@ public void setNormalizedYear(int normalizedYear) { Gregorian() { } + @Override public String getName() { return "gregorian"; } + @Override public Date getCalendarDate() { return getCalendarDate(System.currentTimeMillis(), newCalendarDate()); } + @Override public Date getCalendarDate(long millis) { return getCalendarDate(millis, newCalendarDate()); } + @Override public Date getCalendarDate(long millis, CalendarDate date) { return (Date) super.getCalendarDate(millis, date); } + @Override public Date getCalendarDate(long millis, TimeZone zone) { return getCalendarDate(millis, newCalendarDate(zone)); } + @Override public Date newCalendarDate() { return new Date(); } + @Override public Date newCalendarDate(TimeZone zone) { return new Date(zone); } diff --git a/src/java.base/share/classes/sun/util/calendar/ImmutableGregorianDate.java b/src/java.base/share/classes/sun/util/calendar/ImmutableGregorianDate.java index 3d9b2da548a..4836cab9886 100644 --- a/src/java.base/share/classes/sun/util/calendar/ImmutableGregorianDate.java +++ b/src/java.base/share/classes/sun/util/calendar/ImmutableGregorianDate.java @@ -25,192 +25,238 @@ package sun.util.calendar; +import java.util.Objects; import java.util.TimeZone; -class ImmutableGregorianDate extends BaseCalendar.Date { +/* + * This class is immutable, and thus any methods from the base classes + * that can modify the state are overridden to throw an exception. + */ +final class ImmutableGregorianDate extends BaseCalendar.Date { private final BaseCalendar.Date date; ImmutableGregorianDate(BaseCalendar.Date date) { - if (date == null) { - throw new NullPointerException(); - } - this.date = date; + this.date = Objects.requireNonNull(date); } + @Override public Era getEra() { return date.getEra(); } + @Override public CalendarDate setEra(Era era) { unsupported(); return this; } + @Override public int getYear() { return date.getYear(); } + @Override public CalendarDate setYear(int year) { unsupported(); return this; } + @Override public CalendarDate addYear(int n) { unsupported(); return this; } + @Override public boolean isLeapYear() { return date.isLeapYear(); } + @Override void setLeapYear(boolean leapYear) { unsupported(); } + @Override public int getMonth() { return date.getMonth(); } + @Override public CalendarDate setMonth(int month) { unsupported(); return this; } + @Override public CalendarDate addMonth(int n) { unsupported(); return this; } + @Override public int getDayOfMonth() { return date.getDayOfMonth(); } + @Override public CalendarDate setDayOfMonth(int date) { unsupported(); return this; } + @Override public int getDayOfWeek() { return date.getDayOfWeek(); } + @Override public int getHours() { return date.getHours(); } + @Override public CalendarDate setHours(int hours) { unsupported(); return this; } + @Override public CalendarDate addHours(int n) { unsupported(); return this; } + @Override public int getMinutes() { return date.getMinutes(); } + @Override public CalendarDate setMinutes(int minutes) { unsupported(); return this; } + @Override public int getSeconds() { return date.getSeconds(); } + @Override public CalendarDate setSeconds(int seconds) { unsupported(); return this; } + @Override public int getMillis() { return date.getMillis(); } + @Override public CalendarDate setMillis(int millis) { unsupported(); return this; } + @Override public long getTimeOfDay() { return date.getTimeOfDay(); } + @Override public CalendarDate setDate(int year, int month, int dayOfMonth) { unsupported(); return this; } + @Override public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) { unsupported(); return this; } + @Override protected void setTimeOfDay(long fraction) { unsupported(); } + @Override public boolean isNormalized() { return date.isNormalized(); } + @Override public boolean isDaylightTime() { return date.isDaylightTime(); } + @Override public TimeZone getZone() { return date.getZone(); } + @Override public CalendarDate setZone(TimeZone zoneinfo) { unsupported(); return this; } + @Override public boolean isSameDate(CalendarDate date) { return date.isSameDate(date); } + @Override public boolean equals(Object obj) { if (this == obj) { return true; } - if (!(obj instanceof ImmutableGregorianDate)) { + if (obj instanceof ImmutableGregorianDate igd) { + return date.equals(igd.date); + } else { return false; } - return date.equals(((ImmutableGregorianDate) obj).date); } + @Override public int hashCode() { return date.hashCode(); } + @Override public Object clone() { return super.clone(); } + @Override public String toString() { return date.toString(); } + @Override protected void setDayOfWeek(int dayOfWeek) { unsupported(); } + @Override protected void setNormalized(boolean normalized) { unsupported(); } + @Override public int getZoneOffset() { return date.getZoneOffset(); } + @Override protected void setZoneOffset(int offset) { unsupported(); } + @Override public int getDaylightSaving() { return date.getDaylightSaving(); } + @Override protected void setDaylightSaving(int daylightSaving) { unsupported(); } + @Override public int getNormalizedYear() { return date.getNormalizedYear(); } + @Override public void setNormalizedYear(int normalizedYear) { unsupported(); } diff --git a/src/java.base/share/classes/sun/util/calendar/JulianCalendar.java b/src/java.base/share/classes/sun/util/calendar/JulianCalendar.java index 8129090d295..49bdaa60cd9 100644 --- a/src/java.base/share/classes/sun/util/calendar/JulianCalendar.java +++ b/src/java.base/share/classes/sun/util/calendar/JulianCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ * @author Masayoshi Okutsu * @since 1.5 */ -public class JulianCalendar extends BaseCalendar { +public final class JulianCalendar extends BaseCalendar { private static final int BCE = 0; private static final int CE = 1; @@ -44,17 +44,18 @@ public class JulianCalendar extends BaseCalendar { }; private static final int JULIAN_EPOCH = -1; - private static class Date extends BaseCalendar.Date { - protected Date() { + static final class Date extends BaseCalendar.Date { + Date() { super(); setCache(1, -1L, 365); // January 1, 1 CE (Julian) } - protected Date(TimeZone zone) { + Date(TimeZone zone) { super(zone); setCache(1, -1L, 365); // January 1, 1 CE (Julian) } + @Override public Date setEra(Era era) { if (era == null) { throw new NullPointerException(); @@ -66,10 +67,11 @@ public Date setEra(Era era) { return this; } - protected void setKnownEra(Era era) { + void setKnownEra(Era era) { super.setEra(era); } + @Override public int getNormalizedYear() { if (getEra() == eras[BCE]) { return 1 - getYear(); @@ -81,6 +83,7 @@ public int getNormalizedYear() { // normalized years. This differs from "Calendrical // Calculations" in which the numbering is ..., -2, -1, 1, 2, // ... + @Override public void setNormalizedYear(int year) { if (year <= 0) { setYear(1 - year); @@ -91,6 +94,7 @@ public void setNormalizedYear(int year) { } } + @Override public String toString() { String time = super.toString(); time = time.substring(time.indexOf('T')); @@ -114,30 +118,37 @@ public String toString() { setEras(eras); } + @Override public String getName() { return "julian"; } + @Override public Date getCalendarDate() { return getCalendarDate(System.currentTimeMillis(), newCalendarDate()); } + @Override public Date getCalendarDate(long millis) { return getCalendarDate(millis, newCalendarDate()); } + @Override public Date getCalendarDate(long millis, CalendarDate date) { return (Date) super.getCalendarDate(millis, date); } + @Override public Date getCalendarDate(long millis, TimeZone zone) { return getCalendarDate(millis, newCalendarDate(zone)); } + @Override public Date newCalendarDate() { return new Date(); } + @Override public Date newCalendarDate(TimeZone zone) { return new Date(zone); } @@ -145,6 +156,7 @@ public Date newCalendarDate(TimeZone zone) { /** * @param jyear normalized Julian year */ + @Override public long getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date cache) { boolean isJan1 = month == JANUARY && dayOfMonth == 1; @@ -182,6 +194,7 @@ public long getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date return days; } + @Override public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) { Date jdate = (Date) date; long fd = 4 * (fixedDate - JULIAN_EPOCH) + 1464; @@ -216,18 +229,18 @@ public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) { /** * Returns the normalized Julian year number of the given fixed date. */ + @Override public int getYearFromFixedDate(long fixedDate) { - int year = (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461); - return year; + return (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461); } + @Override public int getDayOfWeek(CalendarDate date) { - // TODO: should replace this with a faster calculation, such - // as cache table lookup - long fixedDate = getFixedDate(date); - return getDayOfWeekFromFixedDate(fixedDate); + // TODO: should replace with faster calculation, e.g. cache table lookup + return getDayOfWeekFromFixedDate(getFixedDate(date)); } + @Override boolean isLeapYear(int jyear) { return CalendarUtils.isJulianLeapYear(jyear); } diff --git a/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java b/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java index 283adca6b59..cb567e8c052 100644 --- a/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java +++ b/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java @@ -36,7 +36,7 @@ * @since 1.6 */ -public class LocalGregorianCalendar extends BaseCalendar { +public final class LocalGregorianCalendar extends BaseCalendar { private static final Era[] JAPANESE_ERAS = { new Era("Meiji", "M", -3218832000000L, true), new Era("Taisho", "T", -1812153600000L, true), @@ -63,13 +63,14 @@ private static boolean isValidEra(Era newEra, Era[] eras) { private String name; private Era[] eras; - public static class Date extends BaseCalendar.Date { + // Used within java.time and java.util + public static final class Date extends BaseCalendar.Date { - protected Date() { + Date() { super(); } - protected Date(TimeZone zone) { + Date(TimeZone zone) { super(zone); } From ef49e6c0d7e4e3a2d7d3d8dcb1edf195b23ce12c Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 21 Sep 2023 21:31:37 +0000 Subject: [PATCH 23/29] 8316629: j.text.DateFormatSymbols setZoneStrings() exception is unhelpful Reviewed-by: naoto --- src/java.base/share/classes/java/text/DateFormatSymbols.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index 231061ac0ec..d89c11f2c5a 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -612,7 +612,8 @@ public void setZoneStrings(String[][] newZoneStrings) { for (int i = 0; i < newZoneStrings.length; ++i) { int len = newZoneStrings[i].length; if (len < 5) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException(String.format( + "Row %s of the input array does not have a length of at least 5", i)); } aCopy[i] = Arrays.copyOf(newZoneStrings[i], len); } From 041510dc21df36d9860f4f0048241c2cabb55ee7 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 21 Sep 2023 22:24:24 +0000 Subject: [PATCH 24/29] 8315486: vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java timed out Reviewed-by: cjplummer, lmesnik --- .../forceEarlyReturn002.java | 25 +++++++++++++++++-- .../forceEarlyReturn002a.java | 24 ++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java index f8ac891b9ff..e66da807669 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java @@ -139,13 +139,34 @@ private void sendCommand(long threadID, Value value, boolean expectError, int er } } + // get thread ID for "startNewThread" command + private long getNewThreadId() throws Exception { + final String debugeeClassSig = "L" + getDebugeeClassName().replace('.', '/') + ";"; + log.display(" getting classID for " + debugeeClassSig); + long classID = debuggee.getReferenceTypeID(debugeeClassSig); + log.display(" got classID: " + classID); + + log.display(" getting testNewThread field value"); + JDWP.Value value = debuggee.getStaticFieldValue(classID, "testNewThread", JDWP.Tag.THREAD); + + long threadID = ((Long)value.getValue()).longValue(); + log.display(" got threadID: " + threadID); + return threadID; + } + private int createThreadStartEventRequest() { try { + long newThreadId = getNewThreadId(); // create command packet and fill requred out data CommandPacket command = new CommandPacket(JDWP.Command.EventRequest.Set); command.addByte(JDWP.EventKind.THREAD_START); command.addByte(JDWP.SuspendPolicy.ALL); - command.addInt(0); + // we want the THREAD_START event only for the test thread + // and not any others that might be started by debuggee VM, + // so add THREAD_ONLY modifier + command.addInt(1); + command.addByte(JDWP.EventModifierKind.THREAD_ONLY); + command.addObjectID(newThreadId); command.setLength(); transport.write(command); @@ -175,7 +196,7 @@ public void doTest() { Value value; value = new Value(JDWP.Tag.INT, 0); - // create command with invalid trheadID, expect INVALID_OBJECT error + // create command with invalid threadID, expect INVALID_OBJECT error sendCommand(-1, value, true, JDWP.Error.INVALID_OBJECT); // create StateTestThread diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java index c6af1dd7811..dc09ffdb7c9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java @@ -57,14 +57,7 @@ public boolean parseCommand(String command) { return true; } else if (command.equals(COMMAND_START_NEW_THREAD)) { - Thread thread = new Thread(new Runnable() { - public void run() { - log.display("Thread exit"); - } - }); - - thread.setName("forceEarlyReturn002a_NewThread"); - thread.start(); + testNewThread.start(); return true; } @@ -72,6 +65,21 @@ public void run() { return false; } + @Override + protected void init(String args[]) { + super.init(args); + + // create thread for "NewThread" command in advance + testNewThread = new Thread(new Runnable() { + public void run() { + log.display("Thread exit"); + } + }); + testNewThread.setName("forceEarlyReturn002a_NewThread"); + } + + private static Thread testNewThread; + private Thread testThreadInNative; private void stopThreadInNative() { From c72f00463fcb1c4a94126932abbc82a2582c10c2 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 21 Sep 2023 23:10:49 +0000 Subject: [PATCH 25/29] 8316456: StackWalker may skip Continuation::yield0 frame mistakenly Reviewed-by: rpressler, pchilanomate --- src/hotspot/share/include/jvm.h | 4 +- src/hotspot/share/prims/jvm.cpp | 14 +- src/hotspot/share/prims/stackwalk.cpp | 121 ++++++-------- src/hotspot/share/prims/stackwalk.hpp | 8 +- .../classes/java/lang/StackStreamFactory.java | 151 ++++++++++-------- .../share/native/libjava/StackStreamFactory.c | 8 +- .../jdk/internal/vm/Continuation/Scoped.java | 10 +- 7 files changed, 153 insertions(+), 163 deletions(-) diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index b6099c2ebcc..049c454c241 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -255,11 +255,11 @@ JVM_ExpandStackFrameInfo(JNIEnv *env, jobject obj); JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode, jint skip_frames, jobject contScope, jobject cont, - jint frame_count, jint start_index, jobjectArray frames); + jint buffer_size, jint start_index, jobjectArray frames); JNIEXPORT jint JNICALL JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor, - jint frame_count, jint start_index, + jint last_batch_count, jint buffer_size, jint start_index, jobjectArray frames); JNIEXPORT void JNICALL diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index b18795f47f7..e8c97351a5f 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -565,7 +565,7 @@ JVM_END JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode, jint skip_frames, jobject contScope, jobject cont, - jint frame_count, jint start_index, jobjectArray frames)) + jint buffer_size, jint start_index, jobjectArray frames)) if (!thread->has_last_Java_frame()) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", nullptr); } @@ -579,19 +579,18 @@ JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jint mode objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); objArrayHandle frames_array_h(THREAD, fa); - int limit = start_index + frame_count; - if (frames_array_h->length() < limit) { + if (frames_array_h->length() < buffer_size) { THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", nullptr); } oop result = StackWalk::walk(stackStream_h, mode, skip_frames, contScope_h, cont_h, - frame_count, start_index, frames_array_h, CHECK_NULL); + buffer_size, start_index, frames_array_h, CHECK_NULL); return JNIHandles::make_local(THREAD, result); JVM_END JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, jlong anchor, - jint frame_count, jint start_index, + jint last_batch_count, jint buffer_size, jint start_index, jobjectArray frames)) // frames array is a ClassFrameInfo[] array when only getting caller reference, // and a StackFrameInfo[] array (or derivative) otherwise. It should never @@ -599,13 +598,12 @@ JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jint mode, j objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); objArrayHandle frames_array_h(THREAD, fa); - int limit = start_index+frame_count; - if (frames_array_h->length() < limit) { + if (frames_array_h->length() < buffer_size) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); } Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); - return StackWalk::fetchNextBatch(stackStream_h, mode, anchor, frame_count, + return StackWalk::fetchNextBatch(stackStream_h, mode, anchor, last_batch_count, buffer_size, start_index, frames_array_h, THREAD); JVM_END diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 619f64085a0..3d5a56fb9c4 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -152,7 +152,7 @@ BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic, // Parameters: // mode Restrict which frames to be decoded. // BaseFrameStream stream of frames -// max_nframes Maximum number of frames to be filled. +// buffer_size Buffer size // start_index Start index to the user-supplied buffers. // frames_array Buffer to store stack frame information in, starting at start_index. // frames array is a ClassFrameInfo[] array when only getting caller @@ -163,13 +163,13 @@ BaseFrameStream* BaseFrameStream::from_current(JavaThread* thread, jlong magic, // Returns the number of frames whose information was transferred into the buffers. // int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream, - int max_nframes, int start_index, + int buffer_size, int start_index, objArrayHandle frames_array, int& end_index, TRAPS) { log_debug(stackwalk)("fill_in_frames limit=%d start=%d frames length=%d", - max_nframes, start_index, frames_array->length()); - assert(max_nframes > 0, "invalid max_nframes"); - assert(start_index + max_nframes <= frames_array->length(), "oob"); + buffer_size, start_index, frames_array->length()); + assert(buffer_size > 0, "invalid buffer_size"); + assert(buffer_size <= frames_array->length(), "oob"); int frames_decoded = 0; for (; !stream.at_end(); stream.next()) { @@ -186,49 +186,27 @@ int StackWalk::fill_in_frames(jint mode, BaseFrameStream& stream, // skip hidden frames for default StackWalker option (i.e. SHOW_HIDDEN_FRAMES // not set) and when StackWalker::getCallerClass is called - LogTarget(Debug, stackwalk) lt; if (!ShowHiddenFrames && skip_hidden_frames(mode)) { if (method->is_hidden()) { - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" skip hidden method: "); - method->print_short_name(&ls); - ls.cr(); - } - - // We end a batch on continuation bottom to let the Java side skip top frames of the next one + log_debug(stackwalk)(" skip hidden method: %s", stream.method()->external_name()); + + // End a batch on continuation bottom to let the Java side to set the continuation to its parent and continue if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break; continue; } } int index = end_index++; - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" %d: frame method: ", index); - method->print_short_name(&ls); - ls.print_cr(" bci=%d", stream.bci()); - } - - // fill in StackFrameInfo and initialize MemberName + log_debug(stackwalk)(" frame %d: %s bci %d", index, stream.method()->external_name(), stream.bci()); stream.fill_frame(index, frames_array, methodHandle(THREAD, method), CHECK_0); - - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" %d: done frame method: ", index); - method->print_short_name(&ls); - } frames_decoded++; - // We end a batch on continuation bottom to let the Java side skip top frames of the next one + // End a batch on continuation bottom to let the Java side to set the continuation to its parent and continue if (stream.continuation() != nullptr && method->intrinsic_id() == vmIntrinsics::_Continuation_enter) break; - if (frames_decoded >= max_nframes) break; + if (end_index >= buffer_size) break; } - log_debug(stackwalk)("fill_in_frames done frames_decoded=%d at_end=%d", frames_decoded, stream.at_end()); + log_debug(stackwalk)("fill_in_frames returns %d at_end=%d", frames_decoded, stream.at_end()); return frames_decoded; } @@ -398,7 +376,7 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame, // mode Stack walking mode. // skip_frames Number of frames to be skipped. // cont_scope Continuation scope to walk (if not in this scope, we'll walk all the way). -// frame_count Number of frames to be traversed. +// buffer_size Buffer size. // start_index Start index to the user-supplied buffers. // frames_array Buffer to store stack frame info in, starting at start_index. // frames array is a ClassFrameInfo[] array when only getting caller @@ -408,13 +386,13 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame, // Returns Object returned from AbstractStackWalker::doStackWalk call. // oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont, - int frame_count, int start_index, objArrayHandle frames_array, + int buffer_size, int start_index, objArrayHandle frames_array, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); // needed to store a continuation in the RegisterMap JavaThread* jt = THREAD; - log_debug(stackwalk)("Start walking: mode " INT32_FORMAT_X " skip %d frames batch size %d", mode, skip_frames, frame_count); + log_debug(stackwalk)("Start walking: mode " INT32_FORMAT_X " skip %d frames, buffer size %d", mode, skip_frames, buffer_size); LogTarget(Debug, stackwalk) lt; if (lt.is_enabled()) { ResourceMark rm(THREAD); @@ -438,17 +416,17 @@ oop StackWalk::walk(Handle stackStream, jint mode, int skip_frames, Handle cont_ RegisterMap::WalkContinuation::include) : RegisterMap(cont(), RegisterMap::UpdateMap::include); LiveFrameStream stream(jt, ®Map, cont_scope, cont); - return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count, + return fetchFirstBatch(stream, stackStream, mode, skip_frames, buffer_size, start_index, frames_array, THREAD); } else { JavaFrameStream stream(jt, mode, cont_scope, cont); - return fetchFirstBatch(stream, stackStream, mode, skip_frames, frame_count, + return fetchFirstBatch(stream, stackStream, mode, skip_frames, buffer_size, start_index, frames_array, THREAD); } } oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, - jint mode, int skip_frames, int frame_count, + jint mode, int skip_frames, int buffer_size, int start_index, objArrayHandle frames_array, TRAPS) { methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); @@ -461,29 +439,14 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { break; } - - LogTarget(Debug, stackwalk) lt; - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" skip "); - stream.method()->print_short_name(&ls); - ls.cr(); - } + log_debug(stackwalk)(" skip %s", stream.method()->external_name()); stream.next(); } // stack frame has been traversed individually and resume stack walk // from the stack frame at depth == skip_frames. for (int n=0; n < skip_frames && !stream.at_end(); stream.next(), n++) { - LogTarget(Debug, stackwalk) lt; - if (lt.is_enabled()) { - ResourceMark rm(THREAD); - LogStream ls(lt); - ls.print(" skip "); - stream.method()->print_short_name(&ls); - ls.cr(); - } + log_debug(stackwalk)(" skip %s", stream.method()->external_name()); } } @@ -491,7 +454,7 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, int numFrames = 0; if (!stream.at_end()) { KeepStackGCProcessedMark keep_stack(THREAD); - numFrames = fill_in_frames(mode, stream, frame_count, start_index, + numFrames = fill_in_frames(mode, stream, buffer_size, start_index, frames_array, end_index, CHECK_NULL); if (numFrames < 1) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", nullptr); @@ -506,7 +469,7 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, JavaCallArguments args(stackStream); args.push_long(stream.address_value()); args.push_int(skip_frames); - args.push_int(frame_count); + args.push_int(numFrames); args.push_int(start_index); args.push_int(end_index); @@ -535,14 +498,15 @@ oop StackWalk::fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, // stackStream StackStream object // mode Stack walking mode. // magic Must be valid value to continue the stack walk -// frame_count Number of frames to be decoded. +// last_batch_count Number of frames fetched in the last batch. +// buffer_size Buffer size. // start_index Start index to the user-supplied buffers. // frames_array Buffer to store StackFrame in, starting at start_index. // -// Returns the end index of frame filled in the buffer. +// Returns the number of frames filled in the buffer. // jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic, - int frame_count, int start_index, + int last_batch_count, int buffer_size, int start_index, objArrayHandle frames_array, TRAPS) { @@ -556,16 +520,15 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic, THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is null", 0L); } - log_debug(stackwalk)("StackWalk::fetchNextBatch frame_count %d existing_stream " - PTR_FORMAT " start %d frames %d", - frame_count, p2i(existing_stream), start_index, frames_array->length()); + log_debug(stackwalk)("StackWalk::fetchNextBatch last_batch_count %d buffer_size %d existing_stream " + PTR_FORMAT " start %d", last_batch_count, + buffer_size, p2i(existing_stream), start_index, frames_array->length()); int end_index = start_index; - if (frame_count <= 0) { - return end_index; // No operation. + if (buffer_size <= start_index) { + return 0; // No operation. } - int count = frame_count + start_index; - assert (frames_array->length() >= count, "not enough space in buffers"); + assert (frames_array->length() >= buffer_size, "frames_array length < buffer_size"); BaseFrameStream& stream = (*existing_stream); if (!stream.at_end()) { @@ -574,17 +537,27 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic, // peeking at a few frames. Take the cost of flushing out any pending deferred GC // processing of the stack. KeepStackGCProcessedMark keep_stack(jt); - stream.next(); // advance past the last frame decoded in previous batch + + // Advance past the last frame decoded in the previous batch. + // If the last batch is empty, it means that the last batch returns after + // it advanced the frame it previously decoded as it reaches the bottom of + // the continuation and it returns to let Java side set the continuation. + // Now this batch starts right at the first frame of another continuation. + if (last_batch_count > 0) { + log_debug(stackwalk)("advanced past %s", stream.method()->external_name()); + stream.next(); + } + if (!stream.at_end()) { - int n = fill_in_frames(mode, stream, frame_count, start_index, + int numFrames = fill_in_frames(mode, stream, buffer_size, start_index, frames_array, end_index, CHECK_0); - if (n < 1 && !skip_hidden_frames(mode)) { + if (numFrames < 1 && !skip_hidden_frames(mode)) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); } - return end_index; + return numFrames; } } - return end_index; + return 0; } void StackWalk::setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, Handle cont, TRAPS) { diff --git a/src/hotspot/share/prims/stackwalk.hpp b/src/hotspot/share/prims/stackwalk.hpp index f918c4427a6..39890e3f158 100644 --- a/src/hotspot/share/prims/stackwalk.hpp +++ b/src/hotspot/share/prims/stackwalk.hpp @@ -143,7 +143,7 @@ class LiveFrameStream : public BaseFrameStream { class StackWalk : public AllStatic { private: static int fill_in_frames(jint mode, BaseFrameStream& stream, - int max_nframes, int start_index, + int buffer_size, int start_index, objArrayHandle frames_array, int& end_index, TRAPS); @@ -160,15 +160,15 @@ class StackWalk : public AllStatic { } static oop walk(Handle stackStream, jint mode, int skip_frames, Handle cont_scope, Handle cont, - int frame_count, int start_index, objArrayHandle frames_array, + int buffer_size, int start_index, objArrayHandle frames_array, TRAPS); static oop fetchFirstBatch(BaseFrameStream& stream, Handle stackStream, - jint mode, int skip_frames, int frame_count, + jint mode, int skip_frames, int buffer_size, int start_index, objArrayHandle frames_array, TRAPS); static jint fetchNextBatch(Handle stackStream, jint mode, jlong magic, - int frame_count, int start_index, + int last_batch_count, int buffer_size, int start_index, objArrayHandle frames_array, TRAPS); static void setContinuation(Handle stackStream, jlong magic, objArrayHandle frames_array, diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index b9ad5ba6cc7..339e0cc11fc 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -192,10 +192,10 @@ protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) { * * Subclass should override this method to change the batch size * - * @param lastBatchFrameCount number of frames in the last batch; or zero + * @param lastBatchSize last batch size * @return suggested batch size */ - protected abstract int batchSize(int lastBatchFrameCount); + protected abstract int batchSize(int lastBatchSize); /* * Returns the next batch size, always >= minimum batch size @@ -203,7 +203,7 @@ protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) { * Subclass may override this method if the minimum batch size is different. */ protected int getNextBatchSize() { - int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount(); + int lastBatchSize = depth == 0 ? 0 : frameBuffer.currentBatchSize(); int nextBatchSize = batchSize(lastBatchSize); if (isDebug) { System.err.println("last batch size = " + lastBatchSize + @@ -312,19 +312,19 @@ final Class peekFrame() { * 2. reuse or expand the allocated buffers * 3. create specialized StackFrame objects */ - private Object doStackWalk(long anchor, int skipFrames, int batchSize, - int bufStartIndex, int bufEndIndex) { + private Object doStackWalk(long anchor, int skipFrames, int numFrames, + int bufStartIndex, int bufEndIndex) { checkState(NEW); frameBuffer.check(skipFrames); if (isDebug) { - System.err.format("doStackWalk: skip %d start %d end %d%n", - skipFrames, bufStartIndex, bufEndIndex); + System.err.format("doStackWalk: skip %d start %d end %d nframes %d%n", + skipFrames, bufStartIndex, bufEndIndex, numFrames); } this.anchor = anchor; // set anchor for this bulk stack frame traversal - frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex); + frameBuffer.setBatch(depth, bufStartIndex, numFrames); // traverse all frames and perform the action on the stack frames, if specified return consumeFrames(); @@ -334,10 +334,8 @@ private Object doStackWalk(long anchor, int skipFrames, int batchSize, * Get next batch of stack frames. */ private int getNextBatch() { - int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize()); - if (!frameBuffer.isActive() - || (nextBatchSize <= 0) + || (depth == maxDepth) || (frameBuffer.isAtBottom() && !hasMoreContinuations())) { if (isDebug) { System.out.format(" more stack walk done%n"); @@ -346,11 +344,21 @@ private int getNextBatch() { return 0; } + // VM ends the batch when it reaches the bottom of a continuation + // i.e. Continuation::enter. The stack walker will set the continuation + // to its parent to continue. + // Note that the current batch could have no stack frame filled. This could + // happen when Continuation::enter is the last element of the frame buffer + // filled in the last batch and it needs to fetch another batch in order to + // detect reaching the bottom. if (frameBuffer.isAtBottom() && hasMoreContinuations()) { + if (isDebug) { + System.out.format(" set continuation to %s%n", continuation.getParent()); + } setContinuation(continuation.getParent()); } - int numFrames = fetchStackFrames(nextBatchSize); + int numFrames = fetchStackFrames(); if (numFrames == 0 && !hasMoreContinuations()) { frameBuffer.freeze(); // done stack walking } @@ -415,34 +423,35 @@ private R beginStackWalk() { return callStackWalk(mode, 0, contScope, continuation, - frameBuffer.curBatchFrameCount(), + frameBuffer.currentBatchSize(), frameBuffer.startIndex(), frameBuffer.frames()); } /* - * Fetches stack frames. + * Fetches a new batch of stack frames. This method returns + * the number of stack frames filled in this batch. * - * @param batchSize number of elements of the frame buffers for this batch - * @return number of frames fetched in this batch + * When it reaches the bottom of a continuation, i.e. Continuation::enter, + * VM ends the batch and let the stack walker to set the continuation + * to its parent and continue the stack walking. It may return zero. */ - private int fetchStackFrames(int batchSize) { + private int fetchStackFrames() { int startIndex = frameBuffer.startIndex(); - frameBuffer.resize(startIndex, batchSize); - - int endIndex = fetchStackFrames(mode, anchor, batchSize, - startIndex, - frameBuffer.frames()); - if (isDebug) { - System.out.format(" more stack walk requesting %d got %d to %d frames%n", - batchSize, frameBuffer.startIndex(), endIndex); - } - int numFrames = endIndex - startIndex; + // If the last batch didn't fetch any frames, keep the current batch size. + int lastBatchFrameCount = frameBuffer.numFrames(); + int batchSize = getNextBatchSize(); + frameBuffer.resize(batchSize); - if (numFrames > 0) { - frameBuffer.setBatch(depth, startIndex, endIndex); + int numFrames = fetchStackFrames(mode, anchor, lastBatchFrameCount, + batchSize, startIndex, + frameBuffer.frames()); + if (isDebug) { + System.out.format(" more stack walk got %d frames start %d batch size %d%n", + numFrames, frameBuffer.startIndex(), batchSize); } + frameBuffer.setBatch(depth, startIndex, numFrames); return numFrames; } @@ -454,7 +463,7 @@ private int fetchStackFrames(int batchSize) { * @param skipframes number of frames to be skipped before filling the frame buffer. * @param contScope the continuation scope to walk. * @param continuation the continuation to walk, or {@code null} if walking a thread. - * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. + * @param bufferSize the buffer size * @param startIndex start index of the frame buffers to be filled. * @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY} * or a {@link StackFrameInfo} (or derivative) array otherwise. @@ -462,7 +471,7 @@ private int fetchStackFrames(int batchSize) { */ private native R callStackWalk(int mode, int skipframes, ContinuationScope contScope, Continuation continuation, - int batchSize, int startIndex, + int bufferSize, int startIndex, T[] frames); /** @@ -470,15 +479,16 @@ private native R callStackWalk(int mode, int skipframes, * * @param mode mode of stack walking * @param anchor - * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. + * @param lastBatchFrameCount the number of frames filled in the last batch. + * @param bufferSize the buffer size * @param startIndex start index of the frame buffers to be filled. * @param frames Either a {@link ClassFrameInfo} array, if mode is {@link #CLASS_INFO_ONLY} * or a {@link StackFrameInfo} (or derivative) array otherwise. * - * @return the end index to the frame buffers + * @return the number of frames filled in this batch */ - private native int fetchStackFrames(int mode, long anchor, - int batchSize, int startIndex, + private native int fetchStackFrames(int mode, long anchor, int lastBatchFrameCount, + int bufferSize, int startIndex, T[] frames); private native void setContinuation(long anchor, T[] frames, Continuation cont); @@ -537,16 +547,18 @@ protected void initFrameBuffer() { } @Override - protected int batchSize(int lastBatchFrameCount) { - if (lastBatchFrameCount == 0) { + protected int batchSize(int lastBatchSize) { + if (lastBatchSize == 0) { // First batch, use estimateDepth if not exceed the large batch size int initialBatchSize = Math.max(walker.estimateDepth()+RESERVED_ELEMENTS, MIN_BATCH_SIZE); return Math.min(initialBatchSize, LARGE_BATCH_SIZE); } else { - if (lastBatchFrameCount > BATCH_SIZE) { - return lastBatchFrameCount; + // expand only if last batch was full and the buffer size <= 32 + // to minimize the number of unneeded frames decoded. + if (lastBatchSize > BATCH_SIZE || !frameBuffer.isFull()) { + return lastBatchSize; } else { - return Math.min(lastBatchFrameCount*2, BATCH_SIZE); + return Math.min(lastBatchSize*2, BATCH_SIZE); } } } @@ -638,21 +650,20 @@ T[] fill(T[] array, int startIndex, int size) { } @Override - void resize(int startIndex, int elements) { + void resize(int size) { if (!isActive()) throw new IllegalStateException("inactive frame buffer can't be resized"); - assert startIndex == START_POS : - "bad start index " + startIndex + " expected " + START_POS; + assert startIndex() == START_POS : + "bad start index " + startIndex() + " expected " + START_POS; - int size = startIndex+elements; if (stackFrames.length < size) { T[] newFrames = allocateArray(size); // copy initial magic... - System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex()); stackFrames = newFrames; } - fill(stackFrames, startIndex, size); + fill(stackFrames, startIndex(), size); currentBatchSize = size; } @@ -762,7 +773,7 @@ protected void initFrameBuffer() { } @Override - protected int batchSize(int lastBatchFrameCount) { + protected int batchSize(int lastBatchSize) { // this method is only called when the caller class is not found in // the first batch. getCallerClass may be invoked via core reflection. // So increase the next batch size as there may be implementation-specific @@ -803,8 +814,7 @@ abstract static class FrameBuffer { // buffers for VM to fill stack frame info int currentBatchSize; // current batch size int origin; // index to the current traversed stack frame - int fence; // index to the last frame in the current batch - + int fence; // index past the last frame of the current batch FrameBuffer(int initialBatchSize) { if (initialBatchSize < MIN_BATCH_SIZE) { throw new IllegalArgumentException(initialBatchSize + @@ -830,16 +840,13 @@ abstract static class FrameBuffer { /** * Resizes the buffers for VM to fill in the next batch of stack frames. - * The next batch will start at the given startIndex with the maximum number - * of elements. * *

Subclass may override this method to manage the allocated buffers. * - * @param startIndex the start index for the first frame of the next batch to fill in. - * @param elements the number of elements for the next batch to fill in. + * @param size new batch size * */ - abstract void resize(int startIndex, int elements); + abstract void resize(int size); /** * Return the class at the given position in the current batch. @@ -871,8 +878,8 @@ F nextStackFrame() { // ------ FrameBuffer implementation ------ - final int curBatchFrameCount() { - return currentBatchSize-START_POS; + final int currentBatchSize() { + return currentBatchSize; } /* @@ -882,6 +889,15 @@ final boolean isEmpty() { return origin >= fence || (origin == START_POS && fence == 0); } + /* + * Returns the number of stack frames filled in the current batch + */ + final int numFrames() { + if (!isActive()) + throw new IllegalStateException(); + return fence - startIndex(); + } + /* * Freezes this frame buffer. The stack stream source is done fetching. */ @@ -892,10 +908,14 @@ final void freeze() { /* * Tests if this frame buffer is active. It is inactive when - * it is done for traversal. All stack frames have been traversed. + * it is done for traversal. */ final boolean isActive() { - return origin > 0; // && (fence == 0 || origin < fence || fence == currentBatchSize); + return origin > 0; + } + + final boolean isFull() { + return fence == currentBatchSize; } /* @@ -918,7 +938,7 @@ final Class next() { if (isDebug) { int index = origin-1; System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index, - Objects.toString(c), index, fence); + c.getName(), index, fence); } return c; } @@ -941,17 +961,16 @@ final int getIndex() { } /* - * Set the start and end index of a new batch of stack frames that have - * been filled in this frame buffer. + * Set a new batch of stack frames that have been filled in this frame buffer. */ - final void setBatch(int depth, int startIndex, int endIndex) { - if (startIndex <= 0 || endIndex <= 0) + final void setBatch(int depth, int startIndex, int numFrames) { + if (startIndex <= 0 || numFrames < 0) throw new IllegalArgumentException("startIndex=" + startIndex - + " endIndex=" + endIndex); + + " numFrames=" + numFrames); this.origin = startIndex; - this.fence = endIndex; - for (int i = START_POS; i < fence; i++) { + this.fence = startIndex + numFrames; + for (int i = startIndex; i < fence; i++) { if (isDebug) System.err.format(" frame %d: %s%n", i, at(i)); if (depth == 0 && filterStackWalkImpl(at(i))) { // filter the frames due to the stack stream implementation origin++; diff --git a/src/java.base/share/native/libjava/StackStreamFactory.c b/src/java.base/share/native/libjava/StackStreamFactory.c index b53cb539c3e..a04ffbd21e6 100644 --- a/src/java.base/share/native/libjava/StackStreamFactory.c +++ b/src/java.base/share/native/libjava/StackStreamFactory.c @@ -56,10 +56,10 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes */ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk (JNIEnv *env, jobject stackstream, jint mode, jint skipFrames, jobject contScope, jobject cont, - jint batchSize, jint startIndex, jobjectArray frames) + jint bufferSize, jint startIndex, jobjectArray frames) { return JVM_CallStackWalk(env, stackstream, mode, skipFrames, contScope, cont, - batchSize, startIndex, frames); + bufferSize, startIndex, frames); } /* @@ -69,10 +69,10 @@ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWa */ JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames (JNIEnv *env, jobject stackstream, jint mode, jlong anchor, - jint batchSize, jint startIndex, + int lastBatchFrameCount, jint bufferSize, jint startIndex, jobjectArray frames) { - return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize, + return JVM_MoreStackWalk(env, stackstream, mode, anchor, lastBatchFrameCount, bufferSize, startIndex, frames); } diff --git a/test/jdk/jdk/internal/vm/Continuation/Scoped.java b/test/jdk/jdk/internal/vm/Continuation/Scoped.java index 0d96aecdea0..b034243d596 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Scoped.java +++ b/test/jdk/jdk/internal/vm/Continuation/Scoped.java @@ -74,15 +74,15 @@ public void test1() { frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("No scope: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), A).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("A: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), B).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("B: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), C).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("C: " + frames); @@ -90,11 +90,11 @@ public void test1() { frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), K).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("K: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), null).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("null: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "yield0", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); } assertEquals(res.get(), 2); } From a1e03463accfe830eef0aa53a806d0d5ba873b24 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Fri, 22 Sep 2023 00:10:06 +0000 Subject: [PATCH 26/29] 8316698: build failure caused by JDK-8316456 Reviewed-by: dcubed, dholmes --- src/hotspot/share/prims/stackwalk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 3d5a56fb9c4..04a50ff611f 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -522,7 +522,7 @@ jint StackWalk::fetchNextBatch(Handle stackStream, jint mode, jlong magic, log_debug(stackwalk)("StackWalk::fetchNextBatch last_batch_count %d buffer_size %d existing_stream " PTR_FORMAT " start %d", last_batch_count, - buffer_size, p2i(existing_stream), start_index, frames_array->length()); + buffer_size, p2i(existing_stream), start_index); int end_index = start_index; if (buffer_size <= start_index) { return 0; // No operation. From 775e22a8a68b3bcedabc673b1d612dee8028d5d0 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Fri, 22 Sep 2023 02:14:52 +0000 Subject: [PATCH 27/29] 8316699: TestDynamicConstant.java fails with release VMs Reviewed-by: dholmes --- .../src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java index 32135e46bc1..ba3a0aaafe8 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java @@ -33,7 +33,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler * jdk.vm.ci.hotspot.test.TestDynamicConstant * @run testng/othervm - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -XX:UseBootstrapCallInfo=3 + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 * jdk.vm.ci.hotspot.test.TestDynamicConstant */ From fe862639e7ce40f5adef0e482b1fb9c718e061a3 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 22 Sep 2023 06:38:45 +0000 Subject: [PATCH 28/29] 8316319: Generational ZGC: The SoftMaxHeapSize might be wrong when CDS decreases the MaxHeapSize Reviewed-by: aboldtch, serb --- src/hotspot/share/gc/x/xArguments.cpp | 4 ++++ src/hotspot/share/gc/x/xArguments.hpp | 1 + .../share/gc/z/shared/zSharedArguments.cpp | 10 ++++++++ .../share/gc/z/shared/zSharedArguments.hpp | 1 + src/hotspot/share/gc/z/zArguments.cpp | 23 +++++++++++-------- src/hotspot/share/gc/z/zArguments.hpp | 1 + 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/x/xArguments.cpp b/src/hotspot/share/gc/x/xArguments.cpp index 8c02c800247..60e78d2c756 100644 --- a/src/hotspot/share/gc/x/xArguments.cpp +++ b/src/hotspot/share/gc/x/xArguments.cpp @@ -37,6 +37,10 @@ void XArguments::initialize_alignments() { HeapAlignment = SpaceAlignment; } +void XArguments::initialize_heap_flags_and_sizes() { + // Nothing extra to do +} + void XArguments::initialize() { // Check mark stack size const size_t mark_stack_space_limit = XAddressSpaceLimit::mark_stack(); diff --git a/src/hotspot/share/gc/x/xArguments.hpp b/src/hotspot/share/gc/x/xArguments.hpp index aaa586a2df2..196dd994cad 100644 --- a/src/hotspot/share/gc/x/xArguments.hpp +++ b/src/hotspot/share/gc/x/xArguments.hpp @@ -31,6 +31,7 @@ class CollectedHeap; class XArguments : AllStatic { public: static void initialize_alignments(); + static void initialize_heap_flags_and_sizes(); static void initialize(); static size_t heap_virtual_to_physical_ratio(); static CollectedHeap* create_heap(); diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp b/src/hotspot/share/gc/z/shared/zSharedArguments.cpp index 8a00a851acb..4d7e9827f18 100644 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp +++ b/src/hotspot/share/gc/z/shared/zSharedArguments.cpp @@ -38,6 +38,16 @@ void ZSharedArguments::initialize_alignments() { } } +void ZSharedArguments::initialize_heap_flags_and_sizes() { + GCArguments::initialize_heap_flags_and_sizes(); + + if (ZGenerational) { + ZArguments::initialize_heap_flags_and_sizes(); + } else { + XArguments::initialize_heap_flags_and_sizes(); + } +} + void ZSharedArguments::initialize() { GCArguments::initialize(); diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp b/src/hotspot/share/gc/z/shared/zSharedArguments.hpp index 74659f581b9..c53f28ee0f9 100644 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp +++ b/src/hotspot/share/gc/z/shared/zSharedArguments.hpp @@ -31,6 +31,7 @@ class CollectedHeap; class ZSharedArguments : public GCArguments { private: virtual void initialize_alignments(); + virtual void initialize_heap_flags_and_sizes(); virtual void initialize(); virtual size_t conservative_max_heap_alignment(); diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index 01ecf8f3fc4..5ebfeb75f89 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -37,6 +37,19 @@ void ZArguments::initialize_alignments() { HeapAlignment = SpaceAlignment; } +void ZArguments::initialize_heap_flags_and_sizes() { + if (!FLAG_IS_CMDLINE(MaxHeapSize) && + !FLAG_IS_CMDLINE(MaxRAMFraction) && + !FLAG_IS_CMDLINE(MaxRAMPercentage) && + !FLAG_IS_CMDLINE(SoftMaxHeapSize)) { + // We are really just guessing how much memory the program needs. + // When that is the case, we don't want the soft and hard limits to be the same + // as it can cause flakyness in the number of GC threads used, in order to keep + // to a random number we just pulled out of thin air. + FLAG_SET_ERGO(SoftMaxHeapSize, MaxHeapSize * 90 / 100); + } +} + void ZArguments::select_max_gc_threads() { // Select number of parallel threads if (FLAG_IS_DEFAULT(ParallelGCThreads)) { @@ -126,16 +139,6 @@ void ZArguments::initialize() { FLAG_SET_ERGO_IF_DEFAULT(ZCollectionIntervalMajor, ZCollectionInterval); } - if (!FLAG_IS_CMDLINE(MaxHeapSize) && - !FLAG_IS_CMDLINE(MaxRAMFraction) && - !FLAG_IS_CMDLINE(MaxRAMPercentage)) { - // We are really just guessing how much memory the program needs. - // When that is the case, we don't want the soft and hard limits to be the same - // as it can cause flakyness in the number of GC threads used, in order to keep - // to a random number we just pulled out of thin air. - FLAG_SET_ERGO_IF_DEFAULT(SoftMaxHeapSize, MaxHeapSize * 90 / 100); - } - if (FLAG_IS_DEFAULT(ZFragmentationLimit)) { FLAG_SET_DEFAULT(ZFragmentationLimit, 5.0); } diff --git a/src/hotspot/share/gc/z/zArguments.hpp b/src/hotspot/share/gc/z/zArguments.hpp index ac1e613d4cc..7d1c00d30d1 100644 --- a/src/hotspot/share/gc/z/zArguments.hpp +++ b/src/hotspot/share/gc/z/zArguments.hpp @@ -34,6 +34,7 @@ class ZArguments : AllStatic { public: static void initialize_alignments(); + static void initialize_heap_flags_and_sizes(); static void initialize(); static size_t heap_virtual_to_physical_ratio(); static CollectedHeap* create_heap(); From 343cc0ce2bba797e206f6b7312018a8c6d1bdb66 Mon Sep 17 00:00:00 2001 From: Yi-Fan Tsai Date: Fri, 22 Sep 2023 07:57:05 +0000 Subject: [PATCH 29/29] 8315576: compiler/codecache/CodeCacheFullCountTest.java fails after JDK-8314837 Reviewed-by: kvn, thartmann --- test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 -- .../codecache/CodeCacheFullCountTest.java | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 562e71f350c..582b86c485d 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -27,8 +27,6 @@ # ############################################################################# -compiler/codecache/CodeCacheFullCountTest.java 8315576 generic-all - vmTestbase/nsk/jvmti/AttachOnDemand/attach020/TestDescription.java 8287324 generic-all vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001/TestDescription.java 8205957 linux-x64,windows-x64 diff --git a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java index ee6866c396d..a9c6b34509e 100644 --- a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java +++ b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java @@ -45,12 +45,20 @@ public static void main(String args[]) throws Throwable { } } - public static void wasteCodeCache() throws Exception { + public static void wasteCodeCache() throws Throwable { URL url = CodeCacheFullCountTest.class.getProtectionDomain().getCodeSource().getLocation(); - for (int i = 0; i < 500; i++) { - ClassLoader cl = new MyClassLoader(url); - refClass(cl.loadClass("SomeClass")); + try { + for (int i = 0; i < 500; i++) { + ClassLoader cl = new MyClassLoader(url); + refClass(cl.loadClass("SomeClass")); + } + } catch (Throwable t) { + // Expose the root cause of the Throwable instance. + while (t.getCause() != null) { + t = t.getCause(); + } + throw t; } } @@ -59,7 +67,7 @@ public static void runTest() throws Throwable { "-XX:ReservedCodeCacheSize=2496k", "-XX:-UseCodeCacheFlushing", "-XX:-MethodFlushing", "CodeCacheFullCountTest", "WasteCodeCache"); OutputAnalyzer oa = ProcessTools.executeProcess(pb); // Ignore adapter creation failures - if (oa.getExitValue() != 0 && !oa.getStderr().contains("Out of space in CodeCache for adapters")) { + if (oa.getExitValue() != 0 && !oa.getOutput().contains("Out of space in CodeCache for adapters")) { oa.reportDiagnosticSummary(); throw new RuntimeException("VM finished with exit code " + oa.getExitValue()); }