From f3b69da55a1ec4857fff1537a80ab1fefee93dac Mon Sep 17 00:00:00 2001 From: Evemose <124714317+Evemose@users.noreply.github.com> Date: Thu, 27 Jun 2024 07:45:18 +0000 Subject: [PATCH 01/85] 8335136: Underscore as parameter name in one-parameter functional types fails to compile Reviewed-by: jlahoda --- .../sun/tools/javac/parser/JavacParser.java | 2 +- .../ExpressionSwitchUnderscoreAfterYield.java | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index ce484e14b05..ef2d71831dc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -2920,7 +2920,7 @@ List blockStatement() { case PLUS: case SUB: case STRINGLITERAL: case CHARLITERAL: case STRINGFRAGMENT: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL: - case NULL: case IDENTIFIER: case TRUE: case FALSE: + case NULL: case IDENTIFIER: case UNDERSCORE: case TRUE: case FALSE: case NEW: case SWITCH: case THIS: case SUPER: case BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, VOID, BOOLEAN: isYieldStatement = true; diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java new file mode 100644 index 00000000000..14f609cc71e --- /dev/null +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8335136 + * @summary Underscore as parameter name in one-parameter functional types fails to compile in yield statement if not enclosed in parentheses + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.ToolBox toolbox.Task + * @run main ExpressionSwitchUnderscoreAfterYield + */ + +import toolbox.*; + +import java.nio.file.Path; +import java.util.List; + +public class ExpressionSwitchUnderscoreAfterYield extends TestRunner { + + private final ToolBox tb = new ToolBox(); + + private final Path ROOT = Path.of("."); + + public ExpressionSwitchUnderscoreAfterYield() { + super(System.err); + } + + public static void main(String[] args) throws Exception { + new ExpressionSwitchUnderscoreAfterYield().runTests(); + } + + protected void runTests() throws Exception { + runTests(f -> { + if (f.getName().endsWith("_ShouldFailToCompile")) { + return new Object[]{ + List.of( + FailParams.UNDERSCORE_YIELDED, + FailParams.ASSIGNMENT_TO_UNDERSCORE_IN_YIELD + ) + }; + } + return new Object[0]; + }); + } + + @Test + public void testUnderscoreAsParameterNameInLambda_ShouldCompileFine() throws Exception { + var code = """ + import java.util.function.*; + \s + public class Test { + public static void main(String[] args) { + Consumer result = switch (1) { + case 1 -> { + yield _ -> {}; + } + default -> null; + }; + } + } + """; + tb.writeJavaFiles(ROOT, code); + new toolbox.JavacTask(tb) + .files(tb.findJavaFiles(ROOT)) + .run(Task.Expect.SUCCESS); + } + + public record FailParams(String code, List expectedDiagnosticMessage) { + public static FailParams UNDERSCORE_YIELDED = new FailParams( + """ + public class Test { + public static void main(String[] args) { + Object result = switch (1) { + case 1 -> { + yield _; + } + default -> null; + }; + } + } + """, + List.of("Test.java:5:23: compiler.err.use.of.underscore.not.allowed.non.variable", "1 error") + ); + + public static FailParams ASSIGNMENT_TO_UNDERSCORE_IN_YIELD = new FailParams( + """ + public class Test { + public static void main(String[] args) { + Object result = switch (1) { + case 1 -> { + yield _ = 1; + } + default -> null; + }; + } + } + """, + List.of("Test.java:5:23: compiler.err.use.of.underscore.not.allowed.non.variable", "1 error") + ); + } + + @Test + public void testUnderscoreAsParameterNameInLambda_ShouldFailToCompile(List params) throws Exception { + for (var param : params) { + tb.writeJavaFiles(ROOT, param.code); + Task.Result result = new JavacTask(tb) + .options("-XDrawDiagnostics") + .files(tb.findJavaFiles(ROOT)) + .run(Task.Expect.FAIL); + tb.checkEqual(param.expectedDiagnosticMessage, result.getOutputLines(Task.OutputKind.DIRECT)); + } + } + +} From 37e7698c29b8673b904945d397f0698ccd16d27b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 27 Jun 2024 07:54:35 +0000 Subject: [PATCH 02/85] 8335154: jcmd VM.classes -verbose=false does not set verbose to false Reviewed-by: dholmes, stuefe --- src/hotspot/share/services/diagnosticCommand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index faabe74a2ff..4b8eae8a413 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -992,7 +992,7 @@ class VM_PrintClasses : public VM_Operation { }; void ClassesDCmd::execute(DCmdSource source, TRAPS) { - VM_PrintClasses vmop(output(), _verbose.is_set()); + VM_PrintClasses vmop(output(), _verbose.value()); VMThread::execute(&vmop); } From 79a23017fc7154738c375fbb12a997525c3bf9e7 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 27 Jun 2024 10:23:55 +0000 Subject: [PATCH 03/85] 8322859: Parallel: Move transform_stack_chunk Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f01d1a85299..390dea4976d 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -249,10 +249,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, // Copy obj Copy::aligned_disjoint_words(cast_from_oop(o), cast_from_oop(new_obj), new_obj_size); - // Parallel GC claims with a release - so other threads might access this object - // after claiming and they should see the "completed" object. - ContinuationGCSupport::transform_stack_chunk(new_obj); - // Now we have to CAS in the header. // Because the forwarding is done with memory_order_relaxed there is no // ordering with the above copy. Clients that get the forwardee must not @@ -271,6 +267,8 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj"); } + ContinuationGCSupport::transform_stack_chunk(new_obj); + // Do the size comparison first with new_obj_size, which we // already have. Hopefully, only a few objects are larger than // _min_array_size_for_chunking, and most of them will be arrays. From 50dd962b0d0fe36634d96dbbd9d94fbc34d9ff7f Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 27 Jun 2024 12:56:26 +0000 Subject: [PATCH 04/85] 8335007: Inline OopMapCache table Reviewed-by: stefank, coleenp, shade --- src/hotspot/share/interpreter/oopMapCache.cpp | 20 ++++++++----------- src/hotspot/share/interpreter/oopMapCache.hpp | 9 ++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 7b60e4869e3..a10f8c439ea 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -445,29 +445,25 @@ inline unsigned int OopMapCache::hash_value_for(const methodHandle& method, int OopMapCacheEntry* volatile OopMapCache::_old_entries = nullptr; OopMapCache::OopMapCache() { - _array = NEW_C_HEAP_ARRAY(OopMapCacheEntry*, _size, mtClass); - for(int i = 0; i < _size; i++) _array[i] = nullptr; + for(int i = 0; i < size; i++) _array[i] = nullptr; } OopMapCache::~OopMapCache() { - assert(_array != nullptr, "sanity check"); // Deallocate oop maps that are allocated out-of-line flush(); - // Deallocate array - FREE_C_HEAP_ARRAY(OopMapCacheEntry*, _array); } OopMapCacheEntry* OopMapCache::entry_at(int i) const { - return Atomic::load_acquire(&(_array[i % _size])); + return Atomic::load_acquire(&(_array[i % size])); } bool OopMapCache::put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old) { - return Atomic::cmpxchg(&_array[i % _size], old, entry) == old; + return Atomic::cmpxchg(&_array[i % size], old, entry) == old; } void OopMapCache::flush() { - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr) { _array[i] = nullptr; // no barrier, only called in OopMapCache destructor @@ -478,7 +474,7 @@ void OopMapCache::flush() { void OopMapCache::flush_obsolete_entries() { assert(SafepointSynchronize::is_at_safepoint(), "called by RedefineClasses in a safepoint"); - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr && !entry->is_empty() && entry->method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want @@ -513,7 +509,7 @@ void OopMapCache::lookup(const methodHandle& method, // Need a critical section to avoid race against concurrent reclamation. { GlobalCounter::CriticalSection cs(Thread::current()); - for (int i = 0; i < _probe_depth; i++) { + for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry *entry = entry_at(probe + i); if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { entry_for->resource_copy(entry); @@ -542,7 +538,7 @@ void OopMapCache::lookup(const methodHandle& method, } // First search for an empty slot - for (int i = 0; i < _probe_depth; i++) { + for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry* entry = entry_at(probe + i); if (entry == nullptr) { if (put_at(probe + i, tmp, nullptr)) { diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 46c85f6e879..a3f5c395f58 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,11 +152,10 @@ class InterpreterOopMap: ResourceObj { class OopMapCache : public CHeapObj { static OopMapCacheEntry* volatile _old_entries; private: - enum { _size = 32, // Use fixed size for now - _probe_depth = 3 // probe depth in case of collisions - }; + static constexpr int size = 32; // Use fixed size for now + static constexpr int probe_depth = 3; // probe depth in case of collisions - OopMapCacheEntry* volatile * _array; + OopMapCacheEntry* volatile _array[size]; unsigned int hash_value_for(const methodHandle& method, int bci) const; OopMapCacheEntry* entry_at(int i) const; From 6b961acb87c29027f2158c6b7a764f1276a0bf52 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 27 Jun 2024 13:03:21 +0000 Subject: [PATCH 05/85] 8333786: Serial: Remove SerialHeap::_incremental_collection_failed Reviewed-by: tschatzl, iwalulya --- .../share/gc/serial/defNewGeneration.cpp | 86 +------------------ .../share/gc/serial/defNewGeneration.hpp | 1 - src/hotspot/share/gc/serial/serialHeap.cpp | 4 +- src/hotspot/share/gc/serial/serialHeap.hpp | 29 ------- 4 files changed, 2 insertions(+), 118 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index be104dce571..b66681170c6 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -578,33 +578,6 @@ HeapWord* DefNewGeneration::block_start(const void* p) const { return block_start_const(to(), p); } -// The last collection bailed out, we are running out of heap space, -// so we try to allocate the from-space, too. -HeapWord* DefNewGeneration::allocate_from_space(size_t size) { - bool should_try_alloc = should_allocate_from_space() || GCLocker::is_active_and_needs_gc(); - - // If the Heap_lock is not locked by this thread, this will be called - // again later with the Heap_lock held. - bool do_alloc = should_try_alloc && (Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread())); - - HeapWord* result = nullptr; - if (do_alloc) { - result = from()->allocate(size); - } - - log_trace(gc, alloc)("DefNewGeneration::allocate_from_space(" SIZE_FORMAT "): will_fail: %s heap_lock: %s free: " SIZE_FORMAT "%s%s returns %s", - size, - SerialHeap::heap()->incremental_collection_will_fail(false /* don't consult_young */) ? - "true" : "false", - Heap_lock->is_locked() ? "locked" : "unlocked", - from()->free(), - should_try_alloc ? "" : " should_allocate_from_space: NOT", - do_alloc ? " Heap_lock is not owned by self" : "", - result == nullptr ? "null" : "object"); - - return result; -} - HeapWord* DefNewGeneration::expand_and_allocate(size_t size, bool is_tlab) { // We don't attempt to expand the young generation (but perhaps we should.) return allocate(size, is_tlab); @@ -707,21 +680,12 @@ bool DefNewGeneration::collect(bool clear_all_soft_refs) { assert(to()->is_empty(), "to space should be empty now"); adjust_desired_tenuring_threshold(); - - assert(!heap->incremental_collection_failed(), "Should be clear"); } else { assert(_promo_failure_scan_stack.is_empty(), "post condition"); _promo_failure_scan_stack.clear(true); // Clear cached segments. remove_forwarding_pointers(); log_info(gc, promotion)("Promotion failed"); - // Add to-space to the list of space to compact - // when a promotion failure has occurred. In that - // case there can be live objects in to-space - // as a result of a partial evacuation of eden - // and from-space. - swap_spaces(); // For uniformity wrt ParNewGeneration. - heap->set_incremental_collection_failed(); _gc_tracer->report_promotion_failed(_promotion_failed_info); @@ -883,51 +847,10 @@ bool DefNewGeneration::collection_attempt_is_safe() { } void DefNewGeneration::gc_epilogue(bool full) { - DEBUG_ONLY(static bool seen_incremental_collection_failed = false;) - assert(!GCLocker::is_active(), "We should not be executing here"); - // Check if the heap is approaching full after a collection has - // been done. Generally the young generation is empty at - // a minimum at the end of a collection. If it is not, then - // the heap is approaching full. - SerialHeap* gch = SerialHeap::heap(); - if (full) { - DEBUG_ONLY(seen_incremental_collection_failed = false;) - if (!collection_attempt_is_safe() && !_eden_space->is_empty()) { - log_trace(gc)("DefNewEpilogue: cause(%s), full, not safe, set_failed, set_alloc_from, clear_seen", - GCCause::to_string(gch->gc_cause())); - gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state - set_should_allocate_from_space(); // we seem to be running out of space - } else { - log_trace(gc)("DefNewEpilogue: cause(%s), full, safe, clear_failed, clear_alloc_from, clear_seen", - GCCause::to_string(gch->gc_cause())); - gch->clear_incremental_collection_failed(); // We just did a full collection - clear_should_allocate_from_space(); // if set - } - } else { -#ifdef ASSERT - // It is possible that incremental_collection_failed() == true - // here, because an attempted scavenge did not succeed. The policy - // is normally expected to cause a full collection which should - // clear that condition, so we should not be here twice in a row - // with incremental_collection_failed() == true without having done - // a full collection in between. - if (!seen_incremental_collection_failed && - gch->incremental_collection_failed()) { - log_trace(gc)("DefNewEpilogue: cause(%s), not full, not_seen_failed, failed, set_seen_failed", - GCCause::to_string(gch->gc_cause())); - seen_incremental_collection_failed = true; - } else if (seen_incremental_collection_failed) { - log_trace(gc)("DefNewEpilogue: cause(%s), not full, seen_failed, will_clear_seen_failed", - GCCause::to_string(gch->gc_cause())); - seen_incremental_collection_failed = false; - } -#endif // ASSERT - } - // update the generation and space performance counters update_counters(); - gch->counters()->update_counters(); + SerialHeap::heap()->counters()->update_counters(); } void DefNewGeneration::update_counters() { @@ -967,13 +890,6 @@ HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) { // Note that since DefNewGeneration supports lock-free allocation, we // have to use it here, as well. HeapWord* result = eden()->par_allocate(word_size); - if (result == nullptr) { - // If the eden is full and the last collection bailed out, we are running - // out of heap space, and we try to allocate the from-space, too. - // allocate_from_space can't be inlined because that would introduce a - // circular dependency at compile time. - result = allocate_from_space(word_size); - } return result; } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index baf565e2862..0cf2545421f 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -225,7 +225,6 @@ class DefNewGeneration: public Generation { } HeapWord* allocate(size_t word_size, bool is_tlab); - HeapWord* allocate_from_space(size_t word_size); HeapWord* par_allocate(size_t word_size, bool is_tlab); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 8dd8a9c0e67..c1fdc1eba1a 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -92,7 +92,6 @@ SerialHeap::SerialHeap() : _old_gen(nullptr), _rem_set(nullptr), _gc_policy_counters(new GCPolicyCounters("Copy:MSC", 2, 2)), - _incremental_collection_failed(false), _young_manager(nullptr), _old_manager(nullptr), _eden_pool(nullptr), @@ -287,8 +286,7 @@ size_t SerialHeap::max_capacity() const { bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const { size_t young_capacity = _young_gen->capacity_before_gc(); return (word_size > heap_word_size(young_capacity)) - || GCLocker::is_active_and_needs_gc() - || incremental_collection_failed(); + || GCLocker::is_active_and_needs_gc(); } HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 0817c6e9eb3..14e0d737c1a 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -91,11 +91,6 @@ class SerialHeap : public CollectedHeap { GCPolicyCounters* _gc_policy_counters; - // Indicates that the most recent previous incremental collection failed. - // The flag is cleared when an action is taken that might clear the - // condition that caused that incremental collection to fail. - bool _incremental_collection_failed; - bool do_young_collection(bool clear_soft_refs); // Reserve aligned space for the heap as needed by the contained generations. @@ -255,29 +250,6 @@ class SerialHeap : public CollectedHeap { // in other generations, it should call this method. void save_marks(); - // Returns true if an incremental collection is likely to fail. - // We optionally consult the young gen, if asked to do so; - // otherwise we base our answer on whether the previous incremental - // collection attempt failed with no corrective action as of yet. - bool incremental_collection_will_fail(bool consult_young) { - // The first disjunct remembers if an incremental collection failed, even - // when we thought (second disjunct) that it would not. - return incremental_collection_failed() || - (consult_young && !_young_gen->collection_attempt_is_safe()); - } - - // If a generation bails out of an incremental collection, - // it sets this flag. - bool incremental_collection_failed() const { - return _incremental_collection_failed; - } - void set_incremental_collection_failed() { - _incremental_collection_failed = true; - } - void clear_incremental_collection_failed() { - _incremental_collection_failed = false; - } - private: // Return true if an allocation should be attempted in the older generation // if it fails in the younger generation. Return false, otherwise. @@ -289,7 +261,6 @@ class SerialHeap : public CollectedHeap { HeapWord* mem_allocate_work(size_t size, bool is_tlab); -private: MemoryPool* _eden_pool; MemoryPool* _survivor_pool; MemoryPool* _old_pool; From d5375c7db658de491c1f5bad053040d21b82941e Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Thu, 27 Jun 2024 13:22:04 +0000 Subject: [PATCH 06/85] 8333308: javap --system handling doesn't work on internal class names Reviewed-by: liach, stuefe --- src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java index d8fa59c2dd0..b797ef73522 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java @@ -867,7 +867,7 @@ private JavaFileObject getClassFileObject(String className) throws IOException { if (moduleLocation != null) { fo = fileManager.getJavaFileForInput(moduleLocation, className, JavaFileObject.Kind.CLASS); } else { - if (className.indexOf('.') > 0) { + if (className.indexOf('.') > 0 || className.indexOf('/') > 0) { //search for classes with a named package in the JDK modules specifed by --system option first try { for (Set locations: fileManager.listLocationsForModules(StandardLocation.SYSTEM_MODULES)) { From 5909d54147355dd7da5786ff39ead4c15816705c Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 27 Jun 2024 14:21:34 +0000 Subject: [PATCH 07/85] 8326820: Metadata artificially kept alive Reviewed-by: eosterlund, stefank, coleenp --- .../share/classfile/classLoaderDataGraph.cpp | 83 ++++++++++--------- .../share/classfile/classLoaderDataGraph.hpp | 13 ++- .../share/classfile/classLoaderStats.cpp | 2 +- .../share/classfile/systemDictionary.hpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 2 +- .../share/prims/jvmtiGetLoadedClasses.cpp | 2 +- 6 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index 2046286651e..adec6dbdeee 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -241,9 +241,14 @@ LockedClassesDo::~LockedClassesDo() { // Iterating over the CLDG needs to be locked because -// unloading can remove entries concurrently soon. -template -class ClassLoaderDataGraphIteratorBase : public StackObj { +// unloading can remove entries concurrently. +// This iterator does not keep the CLD alive. +// Any CLD OopHandles (modules, mirrors, resolved refs) +// resolved must be treated as no keepalive. And requires +// that its CLD's holder is kept alive if they escape the +// caller's safepoint or ClassLoaderDataGraph_lock +// critical section. +class ClassLoaderDataGraph::ClassLoaderDataGraphIterator : public StackObj { ClassLoaderData* _next; Thread* _thread; HandleMark _hm; // clean up handles when this is done. @@ -251,12 +256,8 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { // unless verifying at a safepoint. public: - ClassLoaderDataGraphIteratorBase() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) { - if (keep_alive) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - } else { - assert_at_safepoint(); - } + ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); } ClassLoaderData* get_next() { @@ -266,10 +267,6 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { cld = cld->next(); } if (cld != nullptr) { - if (keep_alive) { - // Keep cld that is being returned alive. - Handle(_thread, cld->holder()); - } _next = cld->next(); } else { _next = nullptr; @@ -278,9 +275,6 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { } }; -using ClassLoaderDataGraphIterator = ClassLoaderDataGraphIteratorBase; -using ClassLoaderDataGraphIteratorNoKeepAlive = ClassLoaderDataGraphIteratorBase; - void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) { ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { @@ -288,13 +282,6 @@ void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) { } } -void ClassLoaderDataGraph::loaded_cld_do_no_keepalive(CLDClosure* cl) { - ClassLoaderDataGraphIteratorNoKeepAlive iter; - while (ClassLoaderData* cld = iter.get_next()) { - cl->do_cld(cld); - } -} - // These functions assume that the caller has locked the ClassLoaderDataGraph_lock // if they are not calling the function from a safepoint. void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) { @@ -318,6 +305,16 @@ void ClassLoaderDataGraph::methods_do(void f(Method*)) { } } +void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData* cld = iter.get_next()) { + // Keep the holder alive. + (void)cld->holder(); + cld->modules_do(f); + } +} + void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { assert_locked_or_safepoint(Module_lock); ClassLoaderDataGraphIterator iter; @@ -334,9 +331,11 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { } } -void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { +void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) { ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { + // Keep the holder alive. + (void)cld->holder(); cld->loaded_classes_do(klass_closure); } } @@ -346,7 +345,7 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { } void ClassLoaderDataGraph::verify_dictionary() { - ClassLoaderDataGraphIteratorNoKeepAlive iter; + ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { if (cld->dictionary() != nullptr) { cld->dictionary()->verify(); @@ -354,26 +353,28 @@ void ClassLoaderDataGraph::verify_dictionary() { } } -#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \ - while (ClassLoaderData* X = iter.get_next()) \ - if (X->dictionary() != nullptr) - void ClassLoaderDataGraph::print_dictionary(outputStream* st) { - FOR_ALL_DICTIONARY(cld) { - st->print("Dictionary for "); - cld->print_value_on(st); - st->cr(); - cld->dictionary()->print_on(st); - st->cr(); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData *cld = iter.get_next()) { + if (cld->dictionary() != nullptr) { + st->print("Dictionary for "); + cld->print_value_on(st); + st->cr(); + cld->dictionary()->print_on(st); + st->cr(); + } } } void ClassLoaderDataGraph::print_table_statistics(outputStream* st) { - FOR_ALL_DICTIONARY(cld) { - ResourceMark rm; // loader_name_and_id - stringStream tempst; - tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); - cld->dictionary()->print_table_statistics(st, tempst.freeze()); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData *cld = iter.get_next()) { + if (cld->dictionary() != nullptr) { + ResourceMark rm; // loader_name_and_id + stringStream tempst; + tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); + cld->dictionary()->print_table_statistics(st, tempst.freeze()); + } } } @@ -550,7 +551,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { } void ClassLoaderDataGraph::verify() { - ClassLoaderDataGraphIteratorNoKeepAlive iter; + ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { cld->verify(); } diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp index 3de2c10850e..a79c6e21089 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -37,10 +37,10 @@ class ClassLoaderDataGraph : public AllStatic { friend class ClassLoaderDataGraphMetaspaceIterator; friend class ClassLoaderDataGraphKlassIteratorAtomic; friend class ClassLoaderDataGraphKlassIteratorStatic; - template - friend class ClassLoaderDataGraphIteratorBase; friend class VMStructs; private: + class ClassLoaderDataGraphIterator; + // All CLDs (except unlinked CLDs) can be reached by walking _head->_next->... static ClassLoaderData* volatile _head; @@ -71,8 +71,12 @@ class ClassLoaderDataGraph : public AllStatic { static void roots_cld_do(CLDClosure* strong, CLDClosure* weak); static void always_strong_cld_do(CLDClosure* cl); // Iteration through CLDG not by GC. + // All the do suffixed functions do not keep the CLD alive. Any CLD OopHandles + // (modules, mirrors, resolved refs) resolved must be treated as no keepalive. + // And requires that its CLD's holder is kept alive if they escape the + // caller's safepoint or ClassLoaderDataGraph_lock critical section. + // The do_keepalive suffixed functions will keep all CLDs alive. static void loaded_cld_do(CLDClosure* cl); - static void loaded_cld_do_no_keepalive(CLDClosure* cl); // klass do // Walking classes through the ClassLoaderDataGraph include array classes. It also includes // classes that are allocated but not loaded, classes that have errors, and scratch classes @@ -81,9 +85,10 @@ class ClassLoaderDataGraph : public AllStatic { static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); static void methods_do(void f(Method*)); + static void modules_do_keepalive(void f(ModuleEntry*)); static void modules_do(void f(ModuleEntry*)); static void packages_do(void f(PackageEntry*)); - static void loaded_classes_do(KlassClosure* klass_closure); + static void loaded_classes_do_keepalive(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(); diff --git a/src/hotspot/share/classfile/classLoaderStats.cpp b/src/hotspot/share/classfile/classLoaderStats.cpp index f09d9968137..6bb49c3a853 100644 --- a/src/hotspot/share/classfile/classLoaderStats.cpp +++ b/src/hotspot/share/classfile/classLoaderStats.cpp @@ -165,7 +165,7 @@ void ClassLoaderStatsClosure::addEmptyParents(oop cl) { void ClassLoaderStatsVMOperation::doit() { ClassLoaderStatsClosure clsc (_out); - ClassLoaderDataGraph::loaded_cld_do_no_keepalive(&clsc); + ClassLoaderDataGraph::loaded_cld_do(&clsc); clsc.print(); } diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 9f65cb593d3..6355de9c4ce 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -177,7 +177,7 @@ class SystemDictionary : AllStatic { static void classes_do(MetaspaceClosure* it); // Iterate over all methods in all klasses - + // Will not keep metadata alive. See ClassLoaderDataGraph::methods_do. static void methods_do(void f(Method*)); // Garbage collection support diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index dc02e8e5cf0..1a6aec4e438 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -2339,7 +2339,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje } // Iterate over all the modules loaded to the system. - ClassLoaderDataGraph::modules_do(&do_module); + ClassLoaderDataGraph::modules_do_keepalive(&do_module); jint len = _tbl->length(); guarantee(len > 0, "at least one module must be present"); diff --git a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp index 8d6a0736afe..c2e970bae73 100644 --- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp +++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp @@ -105,7 +105,7 @@ JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jcla // Iterate through all classes in ClassLoaderDataGraph // and collect them using the LoadedClassesClosure MutexLocker mcld(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::loaded_classes_do(&closure); + ClassLoaderDataGraph::loaded_classes_do_keepalive(&closure); } return closure.get_result(env, classCountPtr, classesPtr); From 4ab7e98c79a1a0b7aba1ca74a8316820c906e70e Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Thu, 27 Jun 2024 15:07:00 +0000 Subject: [PATCH 08/85] 8330842: Support AES CBC with Ciphertext Stealing (CTS) in SunPKCS11 Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao Reviewed-by: valeriep --- .../classes/sun/security/pkcs11/Config.java | 22 ++ .../sun/security/pkcs11/P11Cipher.java | 318 +++++++++++++++--- .../sun/security/pkcs11/SunPKCS11.java | 17 +- .../classes/sun/security/pkcs11/Token.java | 19 +- .../TestCipherTextStealingMultipart.java | 255 ++++++++++++++ .../pkcs11/Cipher/TestSymmCiphers.java | 41 +-- .../pkcs11/Cipher/TestSymmCiphersNoPad.java | 17 +- 7 files changed, 597 insertions(+), 92 deletions(-) create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java index 20726bb8d47..18ccda542a0 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java @@ -164,6 +164,11 @@ public List run() { // Secmod.Module.getProvider() method. private String functionList = null; + // CTS mode variant used by the token, as described in Addendum to NIST + // Special Publication 800-38A, "Recommendation for Block Cipher Modes + // of Operation: Three Variants of Ciphertext Stealing for CBC Mode". + private Token.CTSVariant ctsVariant = null; + // whether to use NSS secmod mode. Implicitly set if nssLibraryDirectory, // nssSecmodDirectory, or nssModule is specified. private boolean nssUseSecmod; @@ -321,6 +326,10 @@ String getFunctionList() { return functionList; } + Token.CTSVariant getCTSVariant() { + return ctsVariant; + } + boolean getNssUseSecmod() { return nssUseSecmod; } @@ -472,6 +481,8 @@ private void parse() throws IOException { allowSingleThreadedModules = parseBooleanEntry(st.sval); case "functionList"-> functionList = parseStringEntry(st.sval); + case "cipherTextStealingVariant"-> + ctsVariant = parseEnumEntry(Token.CTSVariant.class, st.sval); case "nssUseSecmod"-> nssUseSecmod = parseBooleanEntry(st.sval); case "nssLibraryDirectory"-> { @@ -627,6 +638,17 @@ private int parseIntegerEntry(String keyword) throws IOException { return value; } + private > E parseEnumEntry(Class enumClass, + String keyword) throws IOException { + String value = parseStringEntry(keyword); + try { + return Enum.valueOf(enumClass, value); + } catch (IllegalArgumentException ignored) { + throw excToken(keyword + " must be one of " + + Arrays.toString(enumClass.getEnumConstants()) + ", read:"); + } + } + private boolean parseBoolean() throws IOException { String val = parseWord(); return switch (val) { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java index c65c2185a3e..faf1aa9237f 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * Cipher implementation class. This class currently supports * DES, DESede, AES, ARCFOUR, and Blowfish. * - * This class is designed to support ECB, CBC, CTR with NoPadding + * This class is designed to support ECB, CBC, CTR, CTS with NoPadding * and ECB, CBC with PKCS5Padding. It will use its own padding impl * if the native mechanism does not support padding. * @@ -60,17 +60,9 @@ final class P11Cipher extends CipherSpi { private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); - // mode constant for ECB mode - private static final int MODE_ECB = 3; - // mode constant for CBC mode - private static final int MODE_CBC = 4; - // mode constant for CTR mode - private static final int MODE_CTR = 5; - - // padding constant for NoPadding - private static final int PAD_NONE = 5; - // padding constant for PKCS5Padding - private static final int PAD_PKCS5 = 6; + // mode and padding constants + private enum Mode {ECB /* or stream ciphers */, CBC, CTR, CTS} + private enum Pad {NONE, PKCS5} private static interface Padding { // ENC: format the specified buffer with padding bytes and return the @@ -146,14 +138,14 @@ public int unpad(byte[] paddedData, int len) // flag indicating encrypt or decrypt mode private boolean encrypt; - // mode, one of MODE_* above (MODE_ECB for stream ciphers) - private int blockMode; + // mode, Mode.ECB for stream ciphers + private final Mode blockMode; // block size, 0 for stream ciphers private final int blockSize; - // padding type, on of PAD_* above (PAD_NONE for stream ciphers) - private int paddingType; + // padding type, Pad.NONE for stream ciphers + private Pad paddingType; // when the padding is requested but unsupported by the native mechanism, // we use the following to do padding and necessary data buffering. @@ -163,7 +155,7 @@ public int unpad(byte[] paddedData, int len) private byte[] padBuffer; private int padBufferLen; - // original IV, if in MODE_CBC or MODE_CTR + // original IV, if in Mode.CBC, Mode.CTR or Mode.CTS private byte[] iv; // number of bytes buffered internally by the native mechanism and padBuffer @@ -208,8 +200,7 @@ public int unpad(byte[] paddedData, int len) blockSize = 8; } } - this.blockMode = - (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB); + blockMode = algoParts.length > 1 ? parseMode(algoParts[1]) : Mode.ECB; String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding"); String paddingStr = (algoParts.length > 2 ? algoParts[2] : defPadding); @@ -227,20 +218,19 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } - private int parseMode(String mode) throws NoSuchAlgorithmException { + private Mode parseMode(String mode) throws NoSuchAlgorithmException { mode = mode.toUpperCase(Locale.ENGLISH); - return switch (mode) { - case "ECB" -> MODE_ECB; - case "CBC" -> { - if (blockSize == 0) { - throw new NoSuchAlgorithmException - ("CBC mode not supported with stream ciphers"); - } - yield MODE_CBC; - } - case "CTR" -> MODE_CTR; - default -> throw new NoSuchAlgorithmException("Unsupported mode " + mode); - }; + Mode result; + try { + result = Mode.valueOf(mode); + } catch (IllegalArgumentException ignored) { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + if (blockSize == 0 && result != Mode.ECB) { + throw new NoSuchAlgorithmException( + result + " mode not supported with stream ciphers"); + } + return result; } // see JCE spec @@ -250,13 +240,22 @@ protected void engineSetPadding(String padding) padBuffer = null; padding = padding.toUpperCase(Locale.ENGLISH); if (padding.equals("NOPADDING")) { - paddingType = PAD_NONE; + paddingType = Pad.NONE; + if (blockMode == Mode.CTS) { + // Buffer at least two blocks (where the last one may be + // partial). When using NSS, buffer one more block to avoid + // NSS Bug 1823875: "AES CTS decryption does not update + // its own context's IV on full blocks input" + // https://bugzilla.mozilla.org/show_bug.cgi?id=1823875#c2 + int bufferedBlocks = P11Util.isNSS(token) ? 3 : 2; + padBuffer = new byte[bufferedBlocks * blockSize]; + } } else if (padding.equals("PKCS5PADDING")) { - if (this.blockMode == MODE_CTR) { - throw new NoSuchPaddingException - ("PKCS#5 padding not supported with CTR mode"); + if (blockMode == Mode.CTR || blockMode == Mode.CTS) { + throw new NoSuchPaddingException("PKCS#5 padding not " + + "supported with " + blockMode + " mode"); } - paddingType = PAD_PKCS5; + paddingType = Pad.PKCS5; if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD && mechanism != CKM_AES_CBC_PAD) { // no native padding support; use our own padding impl @@ -371,7 +370,7 @@ private void implInit(int opmode, Key key, byte[] iv, // should never happen; checked by Cipher.init() throw new AssertionError("Unknown mode: " + opmode); }; - if (blockMode == MODE_ECB) { // ECB or stream cipher + if (blockMode == Mode.ECB) { // ECB or stream cipher if (iv != null) { if (blockSize == 0) { throw new InvalidAlgorithmParameterException @@ -381,14 +380,12 @@ private void implInit(int opmode, Key key, byte[] iv, ("IV not used in ECB mode"); } } - } else { // MODE_CBC or MODE_CTR + } else { // Mode.CBC, Mode.CTR or Mode.CTS if (iv == null) { if (!encrypt) { - String exMsg = - (blockMode == MODE_CBC ? - "IV must be specified for decryption in CBC mode" : - "IV must be specified for decryption in CTR mode"); - throw new InvalidAlgorithmParameterException(exMsg); + throw new InvalidAlgorithmParameterException( + "IV must be specified for decryption in " + + blockMode + " mode"); } // generate random IV if (random == null) { @@ -433,6 +430,9 @@ private void reset(boolean doCancel) { session = token.releaseSession(session); bytesBuffered = 0; padBufferLen = 0; + if (padBuffer != null) { + Arrays.fill(padBuffer, (byte) 0); + } } } @@ -487,7 +487,7 @@ private void initialize() throws PKCS11Exception { if (session == null) { session = token.getOpSession(); } - CK_MECHANISM mechParams = (blockMode == MODE_CTR ? + CK_MECHANISM mechParams = (blockMode == Mode.CTR ? new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : new CK_MECHANISM(mechanism, iv)); if (encrypt) { @@ -512,7 +512,9 @@ private int updateLength(int inLen) { } int result = inLen + bytesBuffered; - if (blockSize != 0 && blockMode != MODE_CTR) { + if (blockMode == Mode.CTS) { + result -= getCTSMustBeBuffered(result); + } else if (blockSize != 0 && blockMode != Mode.CTR) { // minus the number of bytes in the last incomplete block. result -= (result & (blockSize - 1)); } @@ -526,7 +528,7 @@ private int doFinalLength(int inLen) { } int result = inLen + bytesBuffered; - if (blockSize != 0 && encrypt && paddingType != PAD_NONE) { + if (blockSize != 0 && encrypt && paddingType != Pad.NONE) { // add the number of bytes to make the last block complete. result += (blockSize - (result & (blockSize - 1))); } @@ -604,7 +606,56 @@ private int implUpdate(byte[] in, int inOfs, int inLen, ensureInitialized(); int k = 0; int newPadBufferLen = 0; - if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (blockMode == Mode.CTS) { + // decide how to split the total data (totalInLen) between + // the token (dataForP11Update) and padBuffer + // (newPadBufferLen) + int totalInLen = padBufferLen + inLen; + newPadBufferLen = getCTSMustBeBuffered(totalInLen); + int dataForP11Update = totalInLen - newPadBufferLen; + if (dataForP11Update > 0 && padBufferLen > 0) { + // there is data for the token and part of it is in + // padBuffer + int flushFromPadBuffer; + int fillLen = getBytesToCompleteBlock(padBufferLen); + if (dataForP11Update >= padBufferLen + fillLen) { + // flush the whole padBuffer + if (fillLen > 0) { + // complete the last padBuffer block from the + // input + bufferInputBytes(in, inOfs, fillLen); + inOfs += fillLen; + inLen -= fillLen; + } + flushFromPadBuffer = padBufferLen; + } else { + // There is not enough input data available to + // complete the padBuffer to a multiple of block + // size. Flush part of the padBuffer (up to a + // multiple of blockSize) now. Shift the remaining + // padBuffer data and buffer more up to completing + // newPadBufferLen later. + flushFromPadBuffer = dataForP11Update; + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + 0, out, outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + 0, out, outOfs, outLen); + } + padBufferLen -= flushFromPadBuffer; + if (padBufferLen > 0) { + // shift remaining data to the padBuffer start + System.arraycopy(padBuffer, flushFromPadBuffer, + padBuffer, 0, padBufferLen); + } + } + newPadBufferLen -= padBufferLen; + inLen -= newPadBufferLen; + } else if (paddingObj != null && (!encrypt || reqBlockUpdates)) { if (padBufferLen != 0) { if (padBufferLen != padBuffer.length) { int bufCapacity = padBuffer.length - padBufferLen; @@ -649,7 +700,8 @@ private int implUpdate(byte[] in, int inOfs, int inLen, } } // update 'padBuffer' if using our own padding impl. - if (paddingObj != null && newPadBufferLen > 0) { + if ((blockMode == Mode.CTS || paddingObj != null) && + newPadBufferLen > 0) { bufferInputBytes(in, inOfs + inLen, newPadBufferLen); } bytesBuffered += (inLen - k); @@ -715,7 +767,56 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) int k = 0; int newPadBufferLen = 0; - if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (blockMode == Mode.CTS) { + // decide how to split the total data (totalInLen) between + // the token (dataForP11Update) and padBuffer + // (newPadBufferLen) + int totalInLen = padBufferLen + inLen; + newPadBufferLen = getCTSMustBeBuffered(totalInLen); + int dataForP11Update = totalInLen - newPadBufferLen; + if (dataForP11Update > 0 && padBufferLen > 0) { + // there is data for the token and part of it is in + // padBuffer + int flushFromPadBuffer; + int fillLen = getBytesToCompleteBlock(padBufferLen); + if (dataForP11Update >= padBufferLen + fillLen) { + // flush the whole padBuffer + if (fillLen > 0) { + // complete the last padBuffer block from the + // input + bufferInputBytes(inBuffer, fillLen); + inOfs += fillLen; + inLen -= fillLen; + } + flushFromPadBuffer = padBufferLen; + } else { + // There is not enough input data available to + // complete the padBuffer to a multiple of block + // size. Flush part of the padBuffer (up to a + // multiple of blockSize) now. Shift the remaining + // padBuffer data and buffer more up to completing + // newPadBufferLen later. + flushFromPadBuffer = dataForP11Update; + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + outAddr, outArray, outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + outAddr, outArray, outOfs, outLen); + } + padBufferLen -= flushFromPadBuffer; + if (padBufferLen > 0) { + // shift remaining data to the padBuffer start + System.arraycopy(padBuffer, flushFromPadBuffer, + padBuffer, 0, padBufferLen); + } + } + newPadBufferLen -= padBufferLen; + inLen -= newPadBufferLen; + } else if (paddingObj != null && (!encrypt || reqBlockUpdates)) { if (padBufferLen != 0) { if (padBufferLen != padBuffer.length) { int bufCapacity = padBuffer.length - padBufferLen; @@ -768,7 +869,8 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) } } // update 'padBuffer' if using our own padding impl. - if (paddingObj != null && newPadBufferLen > 0) { + if ((blockMode == Mode.CTS || paddingObj != null) && + newPadBufferLen > 0) { bufferInputBytes(inBuffer, newPadBufferLen); } bytesBuffered += (inLen - k); @@ -830,6 +932,10 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) k += token.p11.C_EncryptUpdate(session.id(), 0, padBuffer, 0, startOff + actualPadLen, 0, out, outOfs + k, outLen - k); + } else if (blockMode == Mode.CTS) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); } // Some implementations such as the NSS Software Token do not // cancel the operation upon a C_EncryptUpdate failure (as @@ -839,6 +945,9 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) doCancel = false; k += token.p11.C_EncryptFinal(session.id(), 0, out, (outOfs + k), (outLen - k)); + if (blockMode == Mode.CTS) { + convertCTSVariant(null, out, outOfs + k); + } } else { // Special handling to match SunJCE provider behavior if (bytesBuffered == 0 && padBufferLen == 0) { @@ -863,8 +972,16 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) k -= actualPadLen; System.arraycopy(padBuffer, 0, out, outOfs, k); } else { + if (blockMode == Mode.CTS) { + convertCTSVariant(null, padBuffer, padBufferLen); + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); + outOfs += k; + outLen -= k; + } doCancel = false; - k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, + k += token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, outLen); } } @@ -928,6 +1045,10 @@ private int implDoFinal(ByteBuffer outBuffer) k += token.p11.C_EncryptUpdate(session.id(), 0, padBuffer, 0, startOff + actualPadLen, outAddr, outArray, outOfs + k, outLen - k); + } else if (blockMode == Mode.CTS) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + outAddr, outArray, outOfs, outLen); } // Some implementations such as the NSS Software Token do not // cancel the operation upon a C_EncryptUpdate failure (as @@ -937,12 +1058,14 @@ private int implDoFinal(ByteBuffer outBuffer) doCancel = false; k += token.p11.C_EncryptFinal(session.id(), outAddr, outArray, (outOfs + k), (outLen - k)); + if (blockMode == Mode.CTS) { + convertCTSVariant(outBuffer, outArray, outOfs + k); + } } else { // Special handling to match SunJCE provider behavior if (bytesBuffered == 0 && padBufferLen == 0) { return 0; } - if (paddingObj != null) { if (padBufferLen != 0) { k = token.p11.C_DecryptUpdate(session.id(), @@ -964,8 +1087,16 @@ private int implDoFinal(ByteBuffer outBuffer) outArray = padBuffer; outOfs = 0; } else { + if (blockMode == Mode.CTS) { + convertCTSVariant(null, padBuffer, padBufferLen); + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + outAddr, outArray, outOfs, outLen); + outOfs += k; + outLen -= k; + } doCancel = false; - k = token.p11.C_DecryptFinal(session.id(), + k += token.p11.C_DecryptFinal(session.id(), outAddr, outArray, outOfs, outLen); } } @@ -988,6 +1119,83 @@ private int implDoFinal(ByteBuffer outBuffer) } } + private int getBytesToCompleteBlock(int availableBytes) { + int partBlock = availableBytes & (blockSize - 1); + return partBlock == 0 ? 0 : blockSize - partBlock; + } + + private int getCTSMustBeBuffered(int availableBytes) { + return Math.min(availableBytes, + padBuffer.length - getBytesToCompleteBlock(availableBytes)); + } + + /** + * The ciphertext ordering for the three variants can be depicted as + * follows, where 'p' is the penultimate block (which may be partial + * or full), and 'f' the full final block: + * + * 'p' is a partial block 'p' is a full block + * ------------------------ --------------------- + * CS1 (NIST) | .... pp ffff | .... pppp ffff + * CS2 (Schneier) | .... ffff pp | .... pppp ffff + * CS3 (Kerberos) | .... ffff pp | .... ffff pppp + * + * After encryption, we get the ciphertext from the token formatted as + * specified in the SunPKCS11 'cipherTextStealingVariant' configuration + * property. Conversely, before decryption, the ciphertext has to be passed + * to the token according to the previous formatting. This method converts + * the ciphertext between the format used by the token and the one used by + * SunJCE's "AES/CTS/NoPadding" implementation (CS3 as described by RFC + * 2040, section 8). + */ + private void convertCTSVariant(ByteBuffer ciphertextBuf, + byte[] ciphertextArr, int ciphertextEnd) { + if (padBufferLen == blockSize) { + // No reordering needed for a single block + return; + } + assert token.ctsVariant != null : "CTS algorithms should not be " + + "registered if the CTS variant of the token is unknown"; + if (token.ctsVariant == Token.CTSVariant.CS3) { + // Already CS3 + return; + } + int pad = padBufferLen % blockSize; + if (token.ctsVariant == Token.CTSVariant.CS2 && pad != 0) { + // CS2 and 'p' is a partial block, equal to CS3 + return; + } + if (ciphertextArr != null) { + ciphertextBuf = ByteBuffer.wrap(ciphertextArr); + } + if (ciphertextBuf != null) { + // No assumptions should be made about the current ciphertextBuf + // position. Additionally, if ciphertextBuf was not created here, + // the position should not be altered. To ensure this, use offsets + // to read and write bytes from the last two blocks (i.e. absolute + // ByteBuffer operations). Other blocks should not be modified. + pad = pad == 0 ? blockSize : pad; + if (encrypt) { + // .... pp[pp] ffff -> .... ffff pp[pp] + swapLastTwoBlocks(ciphertextBuf, ciphertextEnd, pad, blockSize); + } else { + // .... ffff pp[pp] -> .... pp[pp] ffff + swapLastTwoBlocks(ciphertextBuf, ciphertextEnd, blockSize, pad); + } + } + } + + private static void swapLastTwoBlocks(ByteBuffer ciphertextBuf, + int ciphertextEnd, int prevBlockLen, int lastBlockLen) { + // .... prevBlock lastBlock -> .... lastBlock prevBlock + int prevBlockStart = ciphertextEnd - prevBlockLen - lastBlockLen; + byte[] prevBlockBackup = new byte[prevBlockLen]; + ciphertextBuf.get(prevBlockStart, prevBlockBackup); + ciphertextBuf.put(prevBlockStart, ciphertextBuf, + ciphertextEnd - lastBlockLen, lastBlockLen); + ciphertextBuf.put(ciphertextEnd - prevBlockLen, prevBlockBackup); + } + private void handleException(PKCS11Exception e) throws ShortBufferException, IllegalBlockSizeException { if (e.match(CKR_BUFFER_TOO_SMALL)) { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 07aaa1037ea..4d10584fa09 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -860,6 +860,15 @@ private static void register(Descriptor d) { dA(CIP, "AES_256/KWP/NoPadding", P11KeyWrapCipher, m(CKM_AES_KEY_WRAP_KWP)); + d(CIP, "AES/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_128/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_192/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_256/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES/GCM/NoPadding", P11AEADCipher, m(CKM_AES_GCM)); dA(CIP, "AES_128/GCM/NoPadding", P11AEADCipher, @@ -1290,7 +1299,13 @@ private void initToken(CK_SLOT_INFO slotInfo) throws PKCS11Exception { } continue; } - + if (longMech == CKM_AES_CTS && token.ctsVariant == null) { + if (showInfo) { + System.out.println("DISABLED due to an unspecified " + + "cipherTextStealingVariant in configuration"); + } + continue; + } if (brokenMechanisms.contains(longMech)) { if (showInfo) { System.out.println("DISABLED due to known issue with NSS"); diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java index a6f5f0a8764..b9937b7f0b1 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ * @since 1.5 */ final class Token implements Serializable { + public enum CTSVariant {CS1, CS2, CS3} // need to be serializable to allow SecureRandom to be serialized @Serial @@ -65,6 +66,8 @@ final class Token implements Serializable { @SuppressWarnings("serial") // Type of field is not Serializable final Config config; + final transient CTSVariant ctsVariant; + @SuppressWarnings("serial") // Type of field is not Serializable final CK_TOKEN_INFO tokenInfo; @@ -146,6 +149,7 @@ final class Token implements Serializable { config = provider.config; tokenInfo = p11.C_GetTokenInfo(provider.slotID); writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0; + ctsVariant = getCTSVariant(); // create session manager and open a test session SessionManager sessionManager; try { @@ -412,6 +416,19 @@ CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception { return result; } + private CTSVariant getCTSVariant() { + CTSVariant ctsVariant = config.getCTSVariant(); + if (ctsVariant != null) { + return ctsVariant; + } + // 'cipherTextStealingVariant' needs an explicit value for the + // CKM_AES_CTS mechanism to be enabled. In the case of NSS we know + // that this value is 'CS1', so we can set it for the user. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=373108#c7 + // https://github.com/nss-dev/nss/blob/NSS_3_99_RTM/lib/freebl/cts.c#L65 + return P11Util.isNSS(this) ? CTSVariant.CS1 : null; + } + private synchronized byte[] getTokenId() { if (tokenId == null) { SecureRandom random = JCAUtil.getSecureRandom(); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java b/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java new file mode 100644 index 00000000000..87eeb2519f6 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.security.Provider; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.stream.IntStream; + +/* + * @test + * @bug 8330842 + * @summary test AES CTS multipart operations with SunPKCS11 + * @library /test/lib .. + * @run main/othervm/timeout=120 TestCipherTextStealingMultipart + */ + +public class TestCipherTextStealingMultipart extends PKCS11Test { + private static final String LF = System.lineSeparator(); + private static final String ALGORITHM = "AES/CTS/NoPadding"; + private static final int BLOCK_SIZE = 16; + private static final Key KEY = + new SecretKeySpec("AbCdEfGhIjKlMnOp".getBytes(), "AES"); + private static final IvParameterSpec IV = + new IvParameterSpec("1234567890aBcDeF".getBytes()); + + private static final StringBuilder chunksDesc = new StringBuilder(); + private static Provider sunPKCS11; + private static Cipher sunJCECipher; + + private static byte[][] generateChunks(int totalLength, int[] chunkSizes) { + chunksDesc.setLength(0); + chunksDesc.append("Testing with ").append(totalLength) + .append(" bytes distributed in ").append(chunkSizes.length) + .append(" multipart updates:").append(LF); + int byteIdx = 0; + byte[][] plaintextChunks = new byte[chunkSizes.length][]; + for (int chunkIdx = 0; chunkIdx < chunkSizes.length; chunkIdx++) { + byte[] chunk = new byte[chunkSizes[chunkIdx]]; + for (int i = 0; i < chunk.length; i++) { + chunk[i] = (byte) ('A' + byteIdx++ / BLOCK_SIZE); + } + chunksDesc.append(" ").append(repr(chunk)).append(LF); + plaintextChunks[chunkIdx] = chunk; + } + return plaintextChunks; + } + + private static byte[] computeExpected(byte[] jointPlaintext) + throws Exception { + byte[] ciphertext = sunJCECipher.doFinal(jointPlaintext); + if (ciphertext.length != jointPlaintext.length) { + throw new Exception("In CTS mode, ciphertext and plaintext should" + + " have the same length. However, SunJCE's CTS cipher " + + "returned a ciphertext of " + ciphertext.length + " bytes" + + " and plaintext has " + jointPlaintext.length + " bytes."); + } + return ciphertext; + } + + private static byte[] join(byte[][] inputChunks, int totalLength) { + ByteBuffer outputBuf = ByteBuffer.allocate(totalLength); + for (byte[] inputChunk : inputChunks) { + outputBuf.put(inputChunk); + } + return outputBuf.array(); + } + + private static byte[][] split(byte[] input, int[] chunkSizes) { + ByteBuffer inputBuf = ByteBuffer.wrap(input); + byte[][] outputChunks = new byte[chunkSizes.length][]; + for (int chunkIdx = 0; chunkIdx < chunkSizes.length; chunkIdx++) { + byte[] chunk = new byte[chunkSizes[chunkIdx]]; + inputBuf.get(chunk); + outputChunks[chunkIdx] = chunk; + } + return outputChunks; + } + + private enum CheckType {CIPHERTEXT, PLAINTEXT} + + private enum OutputType {BYTE_ARRAY, DIRECT_BYTE_BUFFER} + + private static void check(CheckType checkType, OutputType outputType, + byte[] expected, ByteBuffer actualBuf) throws Exception { + byte[] actual; + if (actualBuf.hasArray()) { + actual = actualBuf.array(); + } else { + actual = new byte[actualBuf.position()]; + actualBuf.position(0).get(actual); + } + if (!Arrays.equals(actual, expected)) { + throw new Exception("After " + switch (checkType) { + case CIPHERTEXT -> "encrypting"; + case PLAINTEXT -> "decrypting"; + } + " into a " + switch (outputType) { + case BYTE_ARRAY -> "byte[]"; + case DIRECT_BYTE_BUFFER -> "direct ByteBuffer"; + } + ", " + checkType.name().toLowerCase() + "s don't match:" + LF + + " Expected: " + repr(expected) + LF + + " Actual: " + repr(actual)); + } + } + + private static ByteBuffer encryptOrDecryptMultipart(int operation, + OutputType outputType, byte[][] inputChunks, int totalLength) + throws Exception { + Cipher cipher = Cipher.getInstance(ALGORITHM, sunPKCS11); + cipher.init(operation, KEY, IV); + ByteBuffer output = null; + int outOfs = 1; + switch (outputType) { + case BYTE_ARRAY -> { + output = ByteBuffer.allocate(totalLength); + for (byte[] inputChunk : inputChunks) { + output.put(cipher.update(inputChunk)); + } + // Check that the output array offset does not affect the + // penultimate block length calculation. + byte[] tmpOut = new byte[cipher.getOutputSize(0) + outOfs]; + cipher.doFinal(tmpOut, outOfs); + output.put(tmpOut, outOfs, tmpOut.length - outOfs); + } + case DIRECT_BYTE_BUFFER -> { + output = ByteBuffer.allocateDirect(totalLength); + for (byte[] inputChunk : inputChunks) { + cipher.update(ByteBuffer.wrap(inputChunk), output); + } + // Check that the output array offset does not affect the + // penultimate block length calculation. + ByteBuffer tmpOut = ByteBuffer.allocateDirect( + cipher.getOutputSize(0) + outOfs); + tmpOut.position(outOfs); + cipher.doFinal(ByteBuffer.allocate(0), tmpOut); + tmpOut.position(outOfs); + output.put(tmpOut); + } + } + return output; + } + + private static void doMultipart(int... chunkSizes) throws Exception { + int totalLength = IntStream.of(chunkSizes).sum(); + byte[][] plaintextChunks = generateChunks(totalLength, chunkSizes); + byte[] jointPlaintext = join(plaintextChunks, totalLength); + byte[] expectedCiphertext = computeExpected(jointPlaintext); + byte[][] ciphertextChunks = split(expectedCiphertext, chunkSizes); + + for (OutputType outputType : OutputType.values()) { + // Encryption test + check(CheckType.CIPHERTEXT, outputType, expectedCiphertext, + encryptOrDecryptMultipart(Cipher.ENCRYPT_MODE, outputType, + plaintextChunks, totalLength)); + // Decryption test + check(CheckType.PLAINTEXT, outputType, jointPlaintext, + encryptOrDecryptMultipart(Cipher.DECRYPT_MODE, outputType, + ciphertextChunks, totalLength)); + } + } + + private static String repr(byte[] data) { + if (data == null) { + return ""; + } + if (data.length == 0) { + return ""; + } + String lenRepr = " (" + data.length + " bytes)"; + for (byte b : data) { + if (b < 32 || b > 126) { + return HexFormat.ofDelimiter(":").formatHex(data) + lenRepr; + } + } + return new String(data, StandardCharsets.US_ASCII) + lenRepr; + } + + private static void initialize() throws Exception { + sunJCECipher = Cipher.getInstance(ALGORITHM, "SunJCE"); + sunJCECipher.init(Cipher.ENCRYPT_MODE, KEY, IV); + } + + public static void main(String[] args) throws Exception { + initialize(); + main(new TestCipherTextStealingMultipart(), args); + } + + @Override + public void main(Provider p) throws Exception { + sunPKCS11 = p; + try { + // Test relevant combinations for 2, 3, and 4 update operations + int aesBSize = 16; + int[] points = new int[]{1, aesBSize - 1, aesBSize, aesBSize + 1}; + for (int size1 : points) { + for (int size2 : points) { + if (size1 + size2 >= aesBSize) { + doMultipart(size1, size2); + } + for (int size3 : points) { + if (size1 + size2 + size3 >= aesBSize) { + doMultipart(size1, size2, size3); + } + for (int size4 : points) { + if (size1 + size2 + size3 + size4 >= aesBSize) { + doMultipart(size1, size2, size3, size4); + } + } + } + } + } + doMultipart(17, 17, 17, 17, 17); + doMultipart(4, 2, 7, 1, 6, 12); + doMultipart(2, 15, 21, 26, 31, 26, 5, 30); + doMultipart(7, 12, 26, 8, 15, 2, 17, 16, 21, 2, 32, 29); + doMultipart(6, 7, 6, 1, 5, 16, 14, 1, 10, 16, 17, 8, 1, 13, 12); + doMultipart(16, 125, 19, 32, 32, 16, 17, + 31, 19, 13, 16, 16, 32, 16, 16); + doMultipart(5, 30, 11, 9, 6, 14, 20, 6, + 5, 18, 31, 33, 15, 29, 7, 9); + doMultipart(105, 8, 21, 27, 30, 101, 15, 20, + 23, 33, 26, 6, 8, 2, 13, 17); + } catch (Exception e) { + System.out.print(chunksDesc); + throw e; + } + System.out.println("TEST PASS - OK"); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java index 2127256b5ec..e0a7d53e1c1 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4898461 6604496 + * @bug 4898461 6604496 8330842 * @summary basic test for symmetric ciphers with padding * @author Valerie Peng * @library /test/lib .. @@ -80,10 +80,11 @@ private static class CI { // class for holding Cipher Information new CI("DESede", "DESede", 408), new CI("AES", "AES", 128), - new CI("AES/CTR/NoPadding", "AES", 3200) + new CI("AES/CTR/NoPadding", "AES", 3200), + new CI("AES/CTS/NoPadding", "AES", 3200), }; - private static StringBuffer debugBuf = new StringBuffer(); + private static final StringBuffer debugBuf = new StringBuffer(); @Override public void main(Provider p) throws Exception { @@ -128,10 +129,7 @@ public void main(Provider p) throws Exception { } } catch (Exception ex) { // print out debug info when exception is encountered - if (debugBuf != null) { - System.out.println(debugBuf.toString()); - debugBuf = new StringBuffer(); - } + System.out.println(debugBuf); throw ex; } } @@ -171,8 +169,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, } byte[] testOut1 = baos.toByteArray(); endTime = System.nanoTime(); - perfOut("stream InBuf + stream OutBuf: " + - (endTime - startTime)); + perfOut("stream InBuf + stream OutBuf", endTime - startTime); match(testOut1, answer); // test#2: Non-direct Buffer in + non-direct Buffer out @@ -184,8 +181,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inBuf, outBuf); cipher.doFinal(inBuf, outBuf); endTime = System.nanoTime(); - perfOut("non-direct InBuf + non-direct OutBuf: " + - (endTime - startTime)); + perfOut("non-direct InBuf + non-direct OutBuf", endTime - startTime); match(outBuf, answer); // test#3: Direct Buffer in + direc Buffer out @@ -197,8 +193,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inDirectBuf, outDirectBuf); cipher.doFinal(inDirectBuf, outDirectBuf); endTime = System.nanoTime(); - perfOut("direct InBuf + direct OutBuf: " + - (endTime - startTime)); + perfOut("direct InBuf + direct OutBuf", endTime - startTime); //debugOut("(post) inputBuf: " + inDirectBuf + "\n"); //debugOut("(post) outputBuf: " + outDirectBuf + "\n"); @@ -215,8 +210,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inDirectBuf, outBuf); cipher.doFinal(inDirectBuf, outBuf); endTime = System.nanoTime(); - perfOut("direct InBuf + non-direct OutBuf: " + - (endTime - startTime)); + perfOut("direct InBuf + non-direct OutBuf", endTime - startTime); match(outBuf, answer); // test#5: Non-direct Buffer in + direct Buffer out @@ -231,26 +225,21 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inBuf, outDirectBuf); cipher.doFinal(inBuf, outDirectBuf); endTime = System.nanoTime(); - perfOut("non-direct InBuf + direct OutBuf: " + - (endTime - startTime)); + perfOut("non-direct InBuf + direct OutBuf", endTime - startTime); //debugOut("(post) inputBuf: " + inBuf + "\n"); //debugOut("(post) outputBuf: " + outDirectBuf + "\n"); match(outDirectBuf, answer); - debugBuf = null; + debugBuf.setLength(0); } - private static void perfOut(String msg) { - if (debugBuf != null) { - debugBuf.append("PERF>" + msg); - } + private static void perfOut(String msg, long elapsed) { + debugOut("PERF> " + msg + ", elapsed: " + elapsed + " ns\n"); } private static void debugOut(String msg) { - if (debugBuf != null) { - debugBuf.append(msg); - } + debugBuf.append(msg); } private static void match(byte[] b1, byte[] b2) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 8f53cda2f6b..2288a5699fb 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4898484 6604496 8001284 + * @bug 4898484 6604496 8001284 8330842 * @summary basic test for symmetric ciphers with no padding * @author Valerie Peng * @library /test/lib .. @@ -68,10 +68,12 @@ private static class CI { // class for holding Cipher Information new CI("AES/CBC/NoPadding", "AES", 4800), new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), new CI("AES/CTR/NoPadding", "AES", 1600), - new CI("AES/CTR/NoPadding", "AES", 65) + new CI("AES/CTR/NoPadding", "AES", 65), + new CI("AES/CTS/NoPadding", "AES", 1600), + new CI("AES/CTS/NoPadding", "AES", 65), }; - private static StringBuffer debugBuf; + private static final StringBuffer debugBuf = new StringBuffer(); @Override public void main(Provider p) throws Exception { @@ -111,9 +113,7 @@ public void main(Provider p) throws Exception { } } catch (Exception ex) { // print out debug info when exception is encountered - if (debugBuf != null) { - System.out.println(debugBuf.toString()); - } + System.out.println(debugBuf); throw ex; } } @@ -122,7 +122,6 @@ private static void test(Cipher cipher, int mode, SecretKey key, AlgorithmParameters params, byte[] in, byte[] answer) throws Exception { // test setup - debugBuf = new StringBuffer(); cipher.init(mode, key, params); int outLen = cipher.getOutputSize(in.length); debugBuf.append("Estimated output size = " + outLen + "\n"); @@ -214,7 +213,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, } match(outBuf, answer); - debugBuf = null; + debugBuf.setLength(0); } private static void match(byte[] b1, byte[] b2) throws Exception { From b6ffb442acb4a222f017868433eff213d9b84ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 27 Jun 2024 15:14:36 +0000 Subject: [PATCH 09/85] 8335135: HttpURLConnection#HttpInputStream does not throw IOException when response is truncated Reviewed-by: dfuchs --- .../classes/sun/net/www/MeteredStream.java | 5 +- .../java/net/Authenticator/BasicTest4.java | 4 +- .../URLConnection/TruncatedFixedResponse.java | 112 ++++++++++++++++++ ...liveStreamCloseWithWrongContentLength.java | 4 +- 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/net/URLConnection/TruncatedFixedResponse.java diff --git a/src/java.base/share/classes/sun/net/www/MeteredStream.java b/src/java.base/share/classes/sun/net/www/MeteredStream.java index d12389416fc..eaa93bba56c 100644 --- a/src/java.base/share/classes/sun/net/www/MeteredStream.java +++ b/src/java.base/share/classes/sun/net/www/MeteredStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,9 @@ private final void justRead(long n) throws IOException { assert isLockHeldByCurrentThread(); if (n == -1) { + if (expected > count) { + throw new IOException("Premature EOF"); + } /* * don't close automatically when mark is set and is valid; diff --git a/test/jdk/java/net/Authenticator/BasicTest4.java b/test/jdk/java/net/Authenticator/BasicTest4.java index 0146651ba6a..becfdb351ab 100644 --- a/test/jdk/java/net/Authenticator/BasicTest4.java +++ b/test/jdk/java/net/Authenticator/BasicTest4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,7 +151,7 @@ public void run () { System.out.println ("checkfor returned " + success); readAll (s); os = s.getOutputStream(); - os.write (reply2.getBytes()); + os.write ((reply2+"HelloAgain").getBytes()); s.close (); if (success) diff --git a/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java b/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java new file mode 100644 index 00000000000..89d80199930 --- /dev/null +++ b/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8335135 + * @library /test/lib + * @summary Check that reading from inputStream throws an IOException + * if the fixed response stream is closed before reading all bytes. + */ + +import jdk.test.lib.net.URIBuilder; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +public class TruncatedFixedResponse implements Runnable { + + ServerSocket ss; + + /* + * Our "http" server to return a truncated fixed response + */ + public void run() { + try { + Socket s = ss.accept(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(s.getInputStream())); + while (true) { + String req = in.readLine(); + if (req.isEmpty()) { + break; + } + } + PrintStream out = new PrintStream( + new BufferedOutputStream(s.getOutputStream())); + + /* send the header */ + out.print("HTTP/1.1 200\r\n"); + out.print("Content-Length: 100\r\n"); + out.print("Content-Type: text/html\r\n"); + out.print("\r\n"); + out.print("Some content, but too short"); + out.close(); + s.close(); + ss.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + TruncatedFixedResponse() throws Exception { + /* start the server */ + ss = new ServerSocket(); + ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + new Thread(this).start(); + + /* establish http connection to server */ + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(ss.getLocalPort()) + .path("/foo") + .toURL(); + HttpURLConnection http = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + + try (InputStream in = http.getInputStream()) { + while (in.read() != -1) { + // discard response + } + throw new AssertionError("Expected IOException was not thrown"); + } catch (IOException ex) { + System.out.println("Got expected exception: " + ex); + } + } + + public static void main(String args[]) throws Exception { + new TruncatedFixedResponse(); + } +} diff --git a/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java b/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java index 32796985a8b..e859d671a67 100644 --- a/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java +++ b/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,7 +173,7 @@ public static void main (String[] args) throws Exception { c=is.read(); System.out.println("client reads: "+c); } catch (IOException ioe) { - is.read (); + System.out.println("client got expected exception: "+ioe); break; } } From 0e6b0cbaaa0d5272f60ee4fe09cf5e247e68c2a8 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 27 Jun 2024 15:38:06 +0000 Subject: [PATCH 10/85] 8334886: jdk/jfr/api/recording/time/TestTimeMultiple.java failed with RuntimeException: getStopTime() > afterStop Reviewed-by: mgronlun --- src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp | 2 -- src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp b/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp index b88ba06bdf7..a35b046e56c 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp @@ -47,8 +47,6 @@ jlong JfrChunk::nanos_now() { const jlong now = seconds * 1000000000 + nanos; if (now > last) { last = now; - } else { - ++last; } return last; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java index 345d2fdcc8d..114052ecea2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java @@ -103,7 +103,6 @@ static long nanosToTicks(long nanos) { static long getChunkStartNanos() { long nanos = JVM.getChunkStartNanos(); - // JVM::getChunkStartNanos() may return a bumped timestamp, +1 ns or +2 ns. // Spin here to give Instant.now() a chance to catch up. awaitUniqueTimestamp(); return nanos; From 9d986a013d01a5bcc0942bcc490258038291c22c Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 27 Jun 2024 16:06:35 +0000 Subject: [PATCH 11/85] 8335220: C2: Missing check for Opaque4 node in EscapeAnalysis Reviewed-by: chagedorn, cslucas --- src/hotspot/share/opto/escape.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 1338bb3c909..2ca722148b6 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -574,18 +574,23 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const { // CmpP/N used by the If controlling the cast. if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) { Node* iff = use->in(0)->in(0); - if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) { + // We may have Opaque4 node between If and Bool nodes. + // Bail out in such case - we need to preserve Opaque4 for correct + // processing predicates after loop opts. + bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp(); + if (can_reduce) { Node* iff_cmp = iff->in(1)->in(1); int opc = iff_cmp->Opcode(); - if ((opc == Op_CmpP || opc == Op_CmpN) && !can_reduce_cmp(n, iff_cmp)) { + can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp); + } + if (!can_reduce) { #ifndef PRODUCT - if (TraceReduceAllocationMerges) { - tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx); - n->dump(5); - } -#endif - return false; + if (TraceReduceAllocationMerges) { + tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx); + n->dump(5); } +#endif + return false; } } } @@ -651,7 +656,12 @@ Node* ConnectionGraph::specialize_cmp(Node* base, Node* curr_ctrl) { if (curr_ctrl == nullptr || curr_ctrl->is_Region()) { con = _igvn->zerocon(t->basic_type()); } else { - Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp + // can_reduce_check_users() verified graph: true/false -> if -> bool -> cmp + assert(curr_ctrl->in(0)->Opcode() == Op_If, "unexpected node %s", curr_ctrl->in(0)->Name()); + Node* bol = curr_ctrl->in(0)->in(1); + assert(bol->is_Bool(), "unexpected node %s", bol->Name()); + Node* curr_cmp = bol->in(1); + assert(curr_cmp->Opcode() == Op_CmpP || curr_cmp->Opcode() == Op_CmpN, "unexpected node %s", curr_cmp->Name()); con = curr_cmp->in(1)->is_Con() ? curr_cmp->in(1) : curr_cmp->in(2); } From 243bae7dc0c3e71c02ffed9e1ee7d436af11d3b9 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 27 Jun 2024 18:25:16 +0000 Subject: [PATCH 12/85] 8304693: Remove -XX:-UseVtableBasedCHA Reviewed-by: kvn, coleenp, dholmes --- src/hotspot/share/ci/ciMethod.cpp | 15 +-- src/hotspot/share/code/dependencies.cpp | 10 +- src/hotspot/share/oops/instanceKlass.cpp | 21 +--- src/hotspot/share/oops/instanceKlass.hpp | 3 - src/hotspot/share/runtime/arguments.cpp | 1 + src/hotspot/share/runtime/globals.hpp | 3 - .../compiler/cha/AbstractRootMethod.java | 2 +- .../jtreg/compiler/cha/DefaultRootMethod.java | 2 +- .../cha/StrengthReduceInterfaceCall.java | 2 +- .../invocationOldCHATests.java | 117 ------------------ test/jtreg-ext/requires/VMProps.java | 1 - 11 files changed, 12 insertions(+), 165 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index aac2a553cda..844ef0a0c03 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -718,17 +718,10 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, { MutexLocker locker(Compile_lock); InstanceKlass* context = actual_recv->get_instanceKlass(); - if (UseVtableBasedCHA) { - target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, - root_m->get_Method(), - callee_holder->get_Klass(), - this->get_Method())); - } else { - if (root_m->is_abstract()) { - return nullptr; // not supported - } - target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, root_m->get_Method())); - } + target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, + root_m->get_Method(), + callee_holder->get_Klass(), + this->get_Method())); assert(target() == nullptr || !target()->is_abstract(), "not allowed"); // %%% Should upgrade this ciMethod API to look for 1 or 2 concrete methods. } diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 26e53ed9027..7d3b744313f 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -113,11 +113,7 @@ void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm, ciKlass* resolved_klass, ciMethod* resolved_method) { check_ctxk(ctxk); check_unique_method(ctxk, uniqm); - if (UseVtableBasedCHA) { - assert_common_4(unique_concrete_method_4, ctxk, uniqm, resolved_klass, resolved_method); - } else { - assert_common_2(unique_concrete_method_2, ctxk, uniqm); - } + assert_common_4(unique_concrete_method_4, ctxk, uniqm, resolved_klass, resolved_method); } void Dependencies::assert_unique_implementor(ciInstanceKlass* ctxk, ciInstanceKlass* uniqk) { @@ -1474,7 +1470,6 @@ class LinkedConcreteMethodFinder : public AbstractClassHierarchyWalker { // Optionally, a method which was previously determined as a unique target (uniqm) is added as a participant // to enable dependency spot-checking and speed up the search. LinkedConcreteMethodFinder(InstanceKlass* resolved_klass, Method* resolved_method, Method* uniqm = nullptr) : AbstractClassHierarchyWalker(nullptr) { - assert(UseVtableBasedCHA, "required"); assert(resolved_klass->is_linked(), "required"); assert(resolved_method->method_holder()->is_linked(), "required"); assert(!resolved_method->can_be_statically_bound(), "no vtable index available"); @@ -1948,7 +1943,6 @@ Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk, Klass* resolved_klass, Method* resolved_method, KlassDepChange* changes) { - assert(UseVtableBasedCHA, "required"); assert(!ctxk->is_interface() || ctxk == resolved_klass, "sanity"); assert(!resolved_method->can_be_statically_bound() || resolved_method == uniqm, "sanity"); assert(resolved_klass->is_subtype_of(resolved_method->method_holder()), "sanity"); @@ -2129,7 +2123,7 @@ Klass* Dependencies::DepStream::check_klass_dependency(KlassDepChange* changes) Dependencies::check_valid_dependency_type(type()); if (changes != nullptr) { - if (UseVtableBasedCHA && changes->is_klass_init_change()) { + if (changes->is_klass_init_change()) { return check_klass_init_dependency(changes->as_klass_init_change()); } else { return check_new_klass_dependency(changes->as_new_klass_change()); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index aa8f47f62df..9c40bc1cee8 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -929,7 +929,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // In case itable verification is ever added. // itable().verify(tty, true); #endif - if (UseVtableBasedCHA && Universe::is_fully_initialized()) { + if (Universe::is_fully_initialized()) { DeoptimizationScope deopt_scope; { // Now mark all code that assumes the class is not linked. @@ -1264,7 +1264,7 @@ void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) // Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock // is grabbed, to ensure that the compiler is not using the class hierarchy. -void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { +void InstanceKlass::add_to_hierarchy(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "must NOT be at safepoint"); DeoptimizationScope deopt_scope; @@ -1290,23 +1290,6 @@ void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { deopt_scope.deoptimize_marked(); } -void InstanceKlass::add_to_hierarchy(JavaThread* current) { - - if (UseVtableBasedCHA || !Universe::is_fully_initialized()) { - add_to_hierarchy_impl(current); - } else { - // In case we are not using CHA based vtables we need to make sure the loaded - // deopt is completed before anyone links this class. - // Linking is done with init_lock held, by loading and deopting with it - // held we make sure the deopt is completed before linking. - Handle h_init_lock(current, init_lock()); - ObjectLocker ol(h_init_lock, current); - add_to_hierarchy_impl(current); - - // This doesn't need a notify because the wait is only on the class initialization path. - } -} - InstanceKlass* InstanceKlass::implementor() const { InstanceKlass* volatile* ik = adr_implementor(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index fe281f95148..6e5d4ac8e7f 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -828,9 +828,6 @@ class InstanceKlass: public Klass { void set_jni_ids(JNIid* ids) { _jni_ids = ids; } JNIid* jni_id_for(int offset); - private: - void add_to_hierarchy_impl(JavaThread* current); - public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index f428403fa30..d353c5a162a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -522,6 +522,7 @@ static SpecialFlag const special_jvm_flags[] = { #endif // X86 { "HeapFirstMaximumCompactionCount", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, + { "UseVtableBasedCHA", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index e4eb8d3e9e9..468e9bd8800 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -968,9 +968,6 @@ const int ObjectAlignmentInBytes = 8; develop(bool, UseCHA, true, \ "Enable CHA") \ \ - product(bool, UseVtableBasedCHA, true, DIAGNOSTIC, \ - "Use vtable information during CHA") \ - \ product(bool, UseTypeProfile, true, \ "Check interpreter profile for historically monomorphic calls") \ \ diff --git a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java index 57f41dece80..6f173fefe1e 100644 --- a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java index ee2dda744e6..1b72399069e 100644 --- a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java index 736fa242bdc..068da4100bd 100644 --- a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java +++ b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java deleted file mode 100644 index 415cd105ee9..00000000000 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019, 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=special - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokespecial/Checker.java invokespecial/ClassGenerator.java invokespecial/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests special - */ - -/* - * @test id=virtual - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokevirtual/Checker.java invokevirtual/ClassGenerator.java invokevirtual/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests virtual - */ - -/* - * @test id=interface - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java invokeinterface/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests interface - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.compiler.InMemoryJavaCompiler; - -public class invocationOldCHATests { - - public static void runTest(String whichTests, String classFileVersion) throws Throwable { - System.out.println("\nOld CHA invocation tests, Tests: " + whichTests + - ", class file version: " + classFileVersion); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128M", - "-Xcomp", "-XX:+UnlockDiagnosticVMOptions", "-XX:-UseVtableBasedCHA", - "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", - whichTests, "--classfile_version=" + classFileVersion); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - try { - output.shouldContain("EXECUTION STATUS: PASSED"); - output.shouldHaveExitValue(0); - } catch (Throwable e) { - System.out.println( - "\nNote that an entry such as 'B.m/C.m' in the failure chart means that" + - " the test case failed because method B.m was invoked but the test " + - "expected method C.m to be invoked. Similarly, a result such as 'AME/C.m'" + - " means that an AbstractMethodError exception was thrown but the test" + - " case expected method C.m to be invoked."); - System.out.println( - "\nAlso note that passing --dump to invoke*.Generator will" + - " dump the generated classes (for debugging purposes).\n"); - - throw e; - } - } - - public static void main(String args[]) throws Throwable { - if (args.length < 1) { - throw new IllegalArgumentException("Should provide the test name"); - } - String testName = args[0]; - - // Get current major class file version and test with it. - byte klassbuf[] = InMemoryJavaCompiler.compile("blah", "public class blah { }"); - int major_version = klassbuf[6] << 8 | klassbuf[7]; - - switch (testName) { - case "special": - runTest("invokespecial.Generator", String.valueOf(major_version)); - break; - case "virtual": - runTest("invokevirtual.Generator", String.valueOf(major_version)); - break; - case "interface": - runTest("invokeinterface.Generator", String.valueOf(major_version)); - break; - default: - throw new IllegalArgumentException("Unknown test name: " + testName); - } - } -} diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index e37646ac6d1..49cc6e14311 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -386,7 +386,6 @@ protected void vmOptFinalFlags(SafeMap map) { vmOptFinalFlag(map, "EliminateAllocations"); vmOptFinalFlag(map, "UseCompressedOops"); vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); - vmOptFinalFlag(map, "UseVtableBasedCHA"); vmOptFinalFlag(map, "ZGenerational"); } From c35e58a5adf06e25a3b482e2be384af95a84f11a Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 27 Jun 2024 20:10:13 +0000 Subject: [PATCH 13/85] 8309634: Resolve CONSTANT_MethodRef at CDS dump time Reviewed-by: matsaave, ccheung --- src/hotspot/share/cds/classListParser.cpp | 2 + src/hotspot/share/cds/classListWriter.cpp | 21 +++- src/hotspot/share/cds/classPrelinker.cpp | 18 ++- src/hotspot/share/cds/dumpAllocStats.cpp | 4 + src/hotspot/share/cds/dumpAllocStats.hpp | 12 ++ .../share/interpreter/interpreterRuntime.cpp | 36 +++++- .../share/interpreter/interpreterRuntime.hpp | 7 +- .../share/interpreter/linkResolver.cpp | 104 +++++++++++++----- .../share/interpreter/linkResolver.hpp | 10 +- src/hotspot/share/oops/cpCache.cpp | 95 +++++++++++++++- src/hotspot/share/oops/cpCache.hpp | 4 +- .../share/oops/resolvedMethodEntry.hpp | 25 +++++ .../resolvedConstants/ResolvedConstants.java | 52 ++++++++- 13 files changed, 348 insertions(+), 42 deletions(-) diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 9ee5f25aa89..b2695ac2e78 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -830,6 +830,8 @@ void ClassListParser::parse_constant_pool_tag() { // ignore break; case JVM_CONSTANT_Fieldref: + case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_InterfaceMethodref: preresolve_fmi = true; break; break; diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 97f0bc3476e..78cd092445b 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -258,15 +258,26 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) { if (field_entries != nullptr) { for (int i = 0; i < field_entries->length(); i++) { ResolvedFieldEntry* rfe = field_entries->adr_at(i); - if (rfe->is_resolved(Bytecodes::_getstatic) || - rfe->is_resolved(Bytecodes::_putstatic) || - rfe->is_resolved(Bytecodes::_getfield) || + if (rfe->is_resolved(Bytecodes::_getfield) || rfe->is_resolved(Bytecodes::_putfield)) { list.at_put(rfe->constant_pool_index(), true); print = true; } } } + + Array* method_entries = cp->cache()->resolved_method_entries(); + if (method_entries != nullptr) { + for (int i = 0; i < method_entries->length(); i++) { + ResolvedMethodEntry* rme = method_entries->adr_at(i); + if (rme->is_resolved(Bytecodes::_invokevirtual) || + rme->is_resolved(Bytecodes::_invokespecial) || + rme->is_resolved(Bytecodes::_invokeinterface)) { + list.at_put(rme->constant_pool_index(), true); + print = true; + } + } + } } if (print) { @@ -276,7 +287,9 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) { if (list.at(i)) { constantTag cp_tag = cp->tag_at(i).value(); assert(cp_tag.value() == JVM_CONSTANT_Class || - cp_tag.value() == JVM_CONSTANT_Fieldref, "sanity"); + cp_tag.value() == JVM_CONSTANT_Fieldref || + cp_tag.value() == JVM_CONSTANT_Methodref|| + cp_tag.value() == JVM_CONSTANT_InterfaceMethodref, "sanity"); stream->print(" %d", i); } } diff --git a/src/hotspot/share/cds/classPrelinker.cpp b/src/hotspot/share/cds/classPrelinker.cpp index 223d3937f93..6b866bac995 100644 --- a/src/hotspot/share/cds/classPrelinker.cpp +++ b/src/hotspot/share/cds/classPrelinker.cpp @@ -89,7 +89,9 @@ bool ClassPrelinker::is_resolution_deterministic(ConstantPool* cp, int cp_index) // currently archive only CP entries that are already resolved. Klass* resolved_klass = cp->resolved_klass_at(cp_index); return resolved_klass != nullptr && is_class_resolution_deterministic(cp->pool_holder(), resolved_klass); - } else if (cp->tag_at(cp_index).is_field()) { + } else if (cp->tag_at(cp_index).is_field() || + cp->tag_at(cp_index).is_method() || + cp->tag_at(cp_index).is_interface_method()) { int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); if (!cp->tag_at(klass_cp_index).is_klass()) { // Not yet resolved @@ -263,6 +265,14 @@ void ClassPrelinker::preresolve_field_and_method_cp_entries(JavaThread* current, CLEAR_PENDING_EXCEPTION; // just ignore } break; + case Bytecodes::_invokespecial: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; // just ignore + } + break; default: break; } @@ -301,6 +311,12 @@ void ClassPrelinker::maybe_resolve_fmi_ref(InstanceKlass* ik, Method* m, Bytecod InterpreterRuntime::resolve_get_put(bc, raw_index, mh, cp, false /*initialize_holder*/, CHECK); break; + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokeinterface: + InterpreterRuntime::cds_resolve_invoke(bc, raw_index, cp, CHECK); + break; + default: ShouldNotReachHere(); } diff --git a/src/hotspot/share/cds/dumpAllocStats.cpp b/src/hotspot/share/cds/dumpAllocStats.cpp index 30ef1597063..a1dac41e322 100644 --- a/src/hotspot/share/cds/dumpAllocStats.cpp +++ b/src/hotspot/share/cds/dumpAllocStats.cpp @@ -110,4 +110,8 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all) { _num_field_cp_entries, _num_field_cp_entries_archived, percent_of(_num_field_cp_entries_archived, _num_field_cp_entries), _num_field_cp_entries_reverted); + msg.info("Method CP entries = %6d, archived = %6d (%5.1f%%), reverted = %6d", + _num_method_cp_entries, _num_method_cp_entries_archived, + percent_of(_num_method_cp_entries_archived, _num_method_cp_entries), + _num_method_cp_entries_reverted); } diff --git a/src/hotspot/share/cds/dumpAllocStats.hpp b/src/hotspot/share/cds/dumpAllocStats.hpp index 424a98aa738..0332be73120 100644 --- a/src/hotspot/share/cds/dumpAllocStats.hpp +++ b/src/hotspot/share/cds/dumpAllocStats.hpp @@ -71,6 +71,9 @@ class DumpAllocStats : public StackObj { int _num_klass_cp_entries; int _num_klass_cp_entries_archived; int _num_klass_cp_entries_reverted; + int _num_method_cp_entries; + int _num_method_cp_entries_archived; + int _num_method_cp_entries_reverted; public: enum { RO = 0, RW = 1 }; @@ -84,6 +87,9 @@ class DumpAllocStats : public StackObj { _num_klass_cp_entries = 0; _num_klass_cp_entries_archived = 0; _num_klass_cp_entries_reverted = 0; + _num_method_cp_entries = 0; + _num_method_cp_entries_archived = 0; + _num_method_cp_entries_reverted = 0; }; CompactHashtableStats* symbol_stats() { return &_symbol_stats; } @@ -122,6 +128,12 @@ class DumpAllocStats : public StackObj { _num_klass_cp_entries_reverted += reverted ? 1 : 0; } + void record_method_cp_entry(bool archived, bool reverted) { + _num_method_cp_entries ++; + _num_method_cp_entries_archived += archived ? 1 : 0; + _num_method_cp_entries_reverted += reverted ? 1 : 0; + } + void print_stats(int ro_all, int rw_all); }; diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index fb779b039f4..4f2eae023f6 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -832,7 +832,6 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt // resolve method CallInfo info; constantPoolHandle pool(current, last_frame.method()->constants()); - ConstantPoolCache* cache = pool->cache(); methodHandle resolved_method; @@ -857,10 +856,18 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt resolved_method = methodHandle(current, info.resolved_method()); } // end JvmtiHideSingleStepping + update_invoke_cp_cache_entry(info, bytecode, resolved_method, pool, method_index); +} + +void InterpreterRuntime::update_invoke_cp_cache_entry(CallInfo& info, Bytecodes::Code bytecode, + methodHandle& resolved_method, + constantPoolHandle& pool, + int method_index) { // Don't allow safepoints until the method is cached. NoSafepointVerifier nsv; // check if link resolution caused cpCache to be updated + ConstantPoolCache* cache = pool->cache(); if (cache->resolved_method_entry_at(method_index)->is_resolved(bytecode)) return; #ifdef ASSERT @@ -912,6 +919,33 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt } } +void InterpreterRuntime::cds_resolve_invoke(Bytecodes::Code bytecode, int method_index, + constantPoolHandle& pool, TRAPS) { + LinkInfo link_info(pool, method_index, bytecode, CHECK); + + if (!link_info.resolved_klass()->is_instance_klass() || InstanceKlass::cast(link_info.resolved_klass())->is_linked()) { + CallInfo call_info; + switch (bytecode) { + case Bytecodes::_invokevirtual: LinkResolver::cds_resolve_virtual_call (call_info, link_info, CHECK); break; + case Bytecodes::_invokeinterface: LinkResolver::cds_resolve_interface_call(call_info, link_info, CHECK); break; + case Bytecodes::_invokespecial: LinkResolver::cds_resolve_special_call (call_info, link_info, CHECK); break; + + default: fatal("Unimplemented: %s", Bytecodes::name(bytecode)); + } + methodHandle resolved_method(THREAD, call_info.resolved_method()); + guarantee(resolved_method->method_holder()->is_linked(), ""); + update_invoke_cp_cache_entry(call_info, bytecode, resolved_method, pool, method_index); + } else { + // FIXME: why a shared class is not linked yet? + // Can't link it here since there are no guarantees it'll be prelinked on the next run. + ResourceMark rm; + InstanceKlass* resolved_iklass = InstanceKlass::cast(link_info.resolved_klass()); + log_info(cds, resolve)("Not resolved: class not linked: %s %s %s", + resolved_iklass->is_shared() ? "is_shared" : "", + resolved_iklass->init_state_name(), + resolved_iklass->external_name()); + } +} // First time execution: Resolve symbols, create a permanent MethodType object. void InterpreterRuntime::resolve_invokehandle(JavaThread* current) { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 3a8db1363df..61041694fc6 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -92,9 +92,11 @@ class InterpreterRuntime: AllStatic { static void resolve_from_cache(JavaThread* current, Bytecodes::Code bytecode); - // Used by ClassListParser. + // Used by ClassPrelinker static void resolve_get_put(Bytecodes::Code bytecode, int field_index, methodHandle& m, constantPoolHandle& pool, bool initialize_holder, TRAPS); + static void cds_resolve_invoke(Bytecodes::Code bytecode, int method_index, + constantPoolHandle& pool, TRAPS); private: // Statics & fields @@ -105,6 +107,9 @@ class InterpreterRuntime: AllStatic { static void resolve_invokehandle (JavaThread* current); static void resolve_invokedynamic(JavaThread* current); + static void update_invoke_cp_cache_entry(CallInfo& info, Bytecodes::Code bytecode, + methodHandle& resolved_method, + constantPoolHandle& pool, int method_index); public: // Synchronization static void monitorenter(JavaThread* current, BasicObjectLock* elem); diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 2c7decfa714..cadc3e8a2e8 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -142,7 +142,9 @@ void CallInfo::set_common(Klass* resolved_klass, CallKind kind, int index, TRAPS) { - assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond"); + if (selected_method.not_null()) { + assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond"); + } _resolved_klass = resolved_klass; _resolved_method = resolved_method; _selected_method = selected_method; @@ -151,7 +153,9 @@ void CallInfo::set_common(Klass* resolved_klass, _resolved_appendix = Handle(); DEBUG_ONLY(verify()); // verify before making side effects - CompilationPolicy::compile_if_required(selected_method, THREAD); + if (selected_method.not_null()) { + CompilationPolicy::compile_if_required(selected_method, THREAD); + } } // utility query for unreflecting a method @@ -1152,6 +1156,10 @@ void LinkResolver::resolve_special_call(CallInfo& result, runtime_resolve_special_method(result, link_info, methodHandle(THREAD, resolved_method), recv, CHECK); } +void LinkResolver::cds_resolve_special_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + resolve_special_call(result, Handle(), link_info, CHECK); +} + // throws linktime exceptions Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info, TRAPS) { @@ -1333,7 +1341,17 @@ void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, Klass* re runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method), link_info.resolved_klass(), recv, receiver_klass, - check_null_and_abstract, CHECK); + check_null_and_abstract, + /*is_abstract_interpretation*/ false, CHECK); +} + +void LinkResolver::cds_resolve_virtual_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + Method* resolved_method = linktime_resolve_virtual_method(link_info, CHECK); + runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method), + link_info.resolved_klass(), + Handle(), nullptr, + /*check_null_and_abstract*/ false, + /*is_abstract_interpretation*/ true, CHECK); } // throws linktime exceptions @@ -1385,7 +1403,11 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, Handle recv, Klass* recv_klass, bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS) { + // is_abstract_interpretation is true IFF CDS is resolving method references without + // running any actual bytecode. Therefore, we don't have an actual recv/recv_klass, so + // we cannot check the actual selected_method (which is not needed by CDS anyway). // setup default return values int vtable_index = Method::invalid_vtable_index; @@ -1406,7 +1428,9 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method); assert(vtable_index >= 0 , "we should have valid vtable index at this point"); - selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + if (!is_abstract_interpretation) { + selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + } } else { // at this point we are sure that resolved_method is virtual and not // a default or miranda method; therefore, it must have a valid vtable index. @@ -1420,31 +1444,40 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, // resolved method, and it can never be changed by an override. if (vtable_index == Method::nonvirtual_vtable_index) { assert(resolved_method->can_be_statically_bound(), "cannot override this method"); - selected_method = resolved_method; + if (!is_abstract_interpretation) { + selected_method = resolved_method; + } } else { - selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + if (!is_abstract_interpretation) { + selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + } } } - // check if method exists - if (selected_method.is_null()) { - throw_abstract_method_error(resolved_method, recv_klass, CHECK); - } + if (!is_abstract_interpretation) { + // check if method exists + if (selected_method.is_null()) { + throw_abstract_method_error(resolved_method, recv_klass, CHECK); + } - // check if abstract - if (check_null_and_abstract && selected_method->is_abstract()) { - // Pass arguments for generating a verbose error message. - throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK); - } + // check if abstract + if (check_null_and_abstract && selected_method->is_abstract()) { + // Pass arguments for generating a verbose error message. + throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK); + } - if (log_develop_is_enabled(Trace, vtables)) { - trace_method_resolution("invokevirtual selected method: receiver-class:", - recv_klass, resolved_klass, selected_method(), - false, vtable_index); + if (log_develop_is_enabled(Trace, vtables)) { + trace_method_resolution("invokevirtual selected method: receiver-class:", + recv_klass, resolved_klass, selected_method(), + false, vtable_index); + } } + // setup result result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); - JFR_ONLY(Jfr::on_resolution(result, CHECK);) + if (selected_method.not_null()) { + JFR_ONLY(Jfr::on_resolution(result, CHECK);) + } } void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* recv_klass, @@ -1454,7 +1487,16 @@ void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK); methodHandle mh(THREAD, resolved_method); runtime_resolve_interface_method(result, mh, link_info.resolved_klass(), - recv, recv_klass, check_null_and_abstract, CHECK); + recv, recv_klass, check_null_and_abstract, + /*is_abstract_interpretation*/ false, CHECK); +} + +void LinkResolver::cds_resolve_interface_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK); + runtime_resolve_interface_method(result, methodHandle(THREAD, resolved_method), link_info.resolved_klass(), + Handle(), nullptr, + /*check_null_and_abstract*/ false, + /*is_abstract_interpretation*/ true, CHECK); } Method* LinkResolver::linktime_resolve_interface_method(const LinkInfo& link_info, @@ -1473,7 +1515,9 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS) { + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS) { + // is_abstract_interpretation -- see comments in runtime_resolve_virtual_method() // check if receiver exists if (check_null_and_abstract && recv.is_null()) { @@ -1481,7 +1525,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, } // check if receiver klass implements the resolved interface - if (!recv_klass->is_subtype_of(resolved_klass)) { + if (!is_abstract_interpretation && !recv_klass->is_subtype_of(resolved_klass)) { ResourceMark rm(THREAD); char buf[200]; jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s", @@ -1490,10 +1534,14 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - methodHandle selected_method = resolved_method; + methodHandle selected_method; + + if (!is_abstract_interpretation) { + selected_method = resolved_method; + } // resolve the method in the receiver class, unless it is private - if (!resolved_method()->is_private()) { + if (!is_abstract_interpretation && !resolved_method()->is_private()) { // do lookup based on receiver klass // This search must match the linktime preparation search for itable initialization // to correctly enforce loader constraints for interface method inheritance. @@ -1539,7 +1587,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, if (resolved_method->has_vtable_index()) { int vtable_index = resolved_method->vtable_index(); log_develop_trace(itables)(" -- vtable index: %d", vtable_index); - assert(vtable_index == selected_method->vtable_index(), "sanity check"); + assert(is_abstract_interpretation || vtable_index == selected_method->vtable_index(), "sanity check"); result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); } else if (resolved_method->has_itable_index()) { int itable_index = resolved_method()->itable_index(); @@ -1556,7 +1604,9 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods) result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK); } - JFR_ONLY(Jfr::on_resolution(result, CHECK);) + if (!is_abstract_interpretation) { + JFR_ONLY(Jfr::on_resolution(result, CHECK);) + } } diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index 80f5d230052..340c7d412d5 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -242,13 +242,15 @@ class LinkResolver: AllStatic { Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS); + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS); static void runtime_resolve_interface_method (CallInfo& result, const methodHandle& resolved_method, Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS); + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS); static bool resolve_previously_linked_invokehandle(CallInfo& result, const LinkInfo& link_info, @@ -325,6 +327,10 @@ class LinkResolver: AllStatic { static void resolve_dynamic_call (CallInfo& result, BootstrapInfo& bootstrap_specifier, TRAPS); + static void cds_resolve_virtual_call (CallInfo& result, const LinkInfo& link_info, TRAPS); + static void cds_resolve_interface_call(CallInfo& result, const LinkInfo& link_info, TRAPS); + static void cds_resolve_special_call (CallInfo& result, const LinkInfo& link_info, TRAPS); + // same as above for compile-time resolution; but returns null handle instead of throwing // an exception on error also, does not initialize klass (i.e., no side effects) static Method* resolve_virtual_call_or_null(Klass* receiver_klass, diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 95c3b8edaf5..817a35959f3 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -46,6 +46,7 @@ #include "oops/compressedOops.hpp" #include "oops/constantPool.inline.hpp" #include "oops/cpCache.inline.hpp" +#include "oops/method.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/resolvedFieldEntry.hpp" @@ -408,9 +409,7 @@ void ConstantPoolCache::remove_unshareable_info() { remove_resolved_field_entries_if_non_deterministic(); } if (_resolved_method_entries != nullptr) { - for (int i = 0; i < _resolved_method_entries->length(); i++) { - resolved_method_entry_at(i)->remove_unshareable_info(); - } + remove_resolved_method_entries_if_non_deterministic(); } } @@ -448,6 +447,96 @@ void ConstantPoolCache::remove_resolved_field_entries_if_non_deterministic() { ArchiveBuilder::alloc_stats()->record_field_cp_entry(archived, resolved && !archived); } } + +void ConstantPoolCache::remove_resolved_method_entries_if_non_deterministic() { + ConstantPool* cp = constant_pool(); + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(cp); + for (int i = 0; i < _resolved_method_entries->length(); i++) { + ResolvedMethodEntry* rme = _resolved_method_entries->adr_at(i); + int cp_index = rme->constant_pool_index(); + bool archived = false; + bool resolved = rme->is_resolved(Bytecodes::_invokevirtual) || + rme->is_resolved(Bytecodes::_invokespecial) || + rme->is_resolved(Bytecodes::_invokeinterface); + + // Just for safety -- this should not happen, but do not archive if we ever see this. + resolved &= !(rme->is_resolved(Bytecodes::_invokehandle) || + rme->is_resolved(Bytecodes::_invokestatic)); + + if (resolved && can_archive_resolved_method(rme)) { + rme->mark_and_relocate(src_cp); + archived = true; + } else { + rme->remove_unshareable_info(); + } + if (resolved) { + LogStreamHandle(Trace, cds, resolve) log; + if (log.is_enabled()) { + ResourceMark rm; + int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); + Symbol* klass_name = cp->klass_name_at(klass_cp_index); + Symbol* name = cp->uncached_name_ref_at(cp_index); + Symbol* signature = cp->uncached_signature_ref_at(cp_index); + log.print("%s%s method CP entry [%3d]: %s %s.%s:%s", + (archived ? "archived" : "reverted"), + (rme->is_resolved(Bytecodes::_invokeinterface) ? " interface" : ""), + cp_index, + cp->pool_holder()->name()->as_C_string(), + klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); + if (archived) { + Klass* resolved_klass = cp->resolved_klass_at(klass_cp_index); + log.print(" => %s%s", + resolved_klass->name()->as_C_string(), + (rme->is_resolved(Bytecodes::_invokestatic) ? " *** static" : "")); + } + } + ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived); + } + } +} + +bool ConstantPoolCache::can_archive_resolved_method(ResolvedMethodEntry* method_entry) { + InstanceKlass* pool_holder = constant_pool()->pool_holder(); + if (!(pool_holder->is_shared_boot_class() || pool_holder->is_shared_platform_class() || + pool_holder->is_shared_app_class())) { + // Archiving resolved cp entries for classes from non-builtin loaders + // is not yet supported. + return false; + } + + if (CDSConfig::is_dumping_dynamic_archive()) { + // InstanceKlass::methods() has been resorted. We need to + // update the vtable_index in method_entry (not implemented) + return false; + } + + if (!method_entry->is_resolved(Bytecodes::_invokevirtual)) { + if (method_entry->method() == nullptr) { + return false; + } + if (method_entry->method()->is_continuation_native_intrinsic()) { + return false; // FIXME: corresponding stub is generated on demand during method resolution (see LinkResolver::resolve_static_call). + } + } + + int cp_index = method_entry->constant_pool_index(); + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(constant_pool()); + assert(src_cp->tag_at(cp_index).is_method() || src_cp->tag_at(cp_index).is_interface_method(), "sanity"); + + if (!ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) { + return false; + } + + if (method_entry->is_resolved(Bytecodes::_invokeinterface) || + method_entry->is_resolved(Bytecodes::_invokevirtual) || + method_entry->is_resolved(Bytecodes::_invokespecial)) { + return true; + } else { + // invokestatic and invokehandle are not supported yet. + return false; + } + +} #endif // INCLUDE_CDS void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) { diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 1f91b194623..c741201c833 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,6 +224,8 @@ class ConstantPoolCache: public MetaspaceObj { #if INCLUDE_CDS void remove_resolved_field_entries_if_non_deterministic(); + void remove_resolved_method_entries_if_non_deterministic(); + bool can_archive_resolved_method(ResolvedMethodEntry* method_entry); #endif // RedefineClasses support diff --git a/src/hotspot/share/oops/resolvedMethodEntry.hpp b/src/hotspot/share/oops/resolvedMethodEntry.hpp index e8445223600..8f49608127f 100644 --- a/src/hotspot/share/oops/resolvedMethodEntry.hpp +++ b/src/hotspot/share/oops/resolvedMethodEntry.hpp @@ -82,6 +82,21 @@ class ResolvedMethodEntry { bool _has_table_index; #endif + void copy_from(const ResolvedMethodEntry& other) { + _method = other._method; + _entry_specific = other._entry_specific; + _cpool_index = other._cpool_index; + _number_of_parameters = other._number_of_parameters; + _tos_state = other._tos_state; + _flags = other._flags; + _bytecode1 = other._bytecode1; + _bytecode2 = other._bytecode2; +#ifdef ASSERT + _has_interface_klass = other._has_interface_klass; + _has_table_index = other._has_table_index; +#endif + } + // Constructors public: ResolvedMethodEntry(u2 cpi) : @@ -99,6 +114,16 @@ class ResolvedMethodEntry { ResolvedMethodEntry() : ResolvedMethodEntry(0) {} + ResolvedMethodEntry(const ResolvedMethodEntry& other) { + copy_from(other); + } + + ResolvedMethodEntry& operator=(const ResolvedMethodEntry& other) { + copy_from(other); + return *this; + } + + // Bit shift to get flags enum { is_vfinal_shift = 0, diff --git a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java index 96744b546a8..474fa65d6ea 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java @@ -54,6 +54,8 @@ public static void main(String[] args) throws Exception { "-cp", appJar, "-Xlog:cds+resolve=trace"); CDSTestUtils.createArchiveAndCheck(opts) + // Class References --- + // Always resolve reference when a class references itself .shouldMatch("cds,resolve.*archived klass.* ResolvedConstantsApp app => ResolvedConstantsApp app") @@ -70,6 +72,8 @@ public static void main(String[] args) throws Exception { // class yet (i.e., there's no initiaited class entry for System in the app loader's dictionary) .shouldMatch("cds,resolve.*reverted klass.* ResolvedConstantsApp .*java/lang/System") + // Field References --- + // Always resolve references to fields in the current class or super class(es) .shouldMatch("cds,resolve.*archived field.* ResolvedConstantsBar => ResolvedConstantsBar.b:I") .shouldMatch("cds,resolve.*archived field.* ResolvedConstantsBar => ResolvedConstantsBar.a:I") @@ -80,11 +84,45 @@ public static void main(String[] args) throws Exception { .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsFoo ResolvedConstantsBar.a:I") .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsFoo ResolvedConstantsBar.b:I") - // Do not resolve field references to unrelated classes .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsApp ResolvedConstantsBar.a:I") .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsApp ResolvedConstantsBar.b:I") + // Method References --- + + // Should resolve references to own constructor + .shouldMatch("cds,resolve.*archived method .* ResolvedConstantsApp ResolvedConstantsApp.:") + // Should resolve references to super constructor + .shouldMatch("cds,resolve.*archived method .* ResolvedConstantsApp java/lang/Object.:") + + // Should resolve interface methods in VM classes + .shouldMatch("cds,resolve.*archived interface method .* ResolvedConstantsApp java/lang/Runnable.run:") + + // Should resolve references to own non-static method (private or public) + .shouldMatch("archived method.*: ResolvedConstantsBar ResolvedConstantsBar.doBar:") + .shouldMatch("archived method.*: ResolvedConstantsApp ResolvedConstantsApp.privateInstanceCall:") + .shouldMatch("archived method.*: ResolvedConstantsApp ResolvedConstantsApp.publicInstanceCall:") + + // Should not resolve references to static method + .shouldNotMatch(" archived method CP entry.*: ResolvedConstantsApp ResolvedConstantsApp.staticCall:") + + // Should resolve references to method in super type + .shouldMatch(" archived method CP entry.*: ResolvedConstantsBar ResolvedConstantsFoo.doBar:") + + // App class cannot resolve references to methods in boot classes: + // When the app class loader tries to resolve a class X that's normally loaded by + // the boot loader, it's possible for the app class loader to get a different copy of + // X (by using MethodHandles.Lookup.defineClass(), etc). Therefore, let's be on + // the side of safety and revert all such references. + // + // This will be addressed in JDK-8315737. + .shouldMatch("reverted method.*: ResolvedConstantsApp java/io/PrintStream.println:") + .shouldMatch("reverted method.*: ResolvedConstantsBar java/lang/Class.getName:") + + // Should not resolve methods in unrelated classes. + .shouldMatch("reverted method.*: ResolvedConstantsApp ResolvedConstantsBar.doit:") + + // End --- ; } } @@ -92,7 +130,11 @@ public static void main(String[] args) throws Exception { class ResolvedConstantsApp implements Runnable { public static void main(String args[]) { System.out.println("Hello ResolvedConstantsApp"); - Object a = new ResolvedConstantsApp(); + ResolvedConstantsApp app = new ResolvedConstantsApp(); + ResolvedConstantsApp.staticCall(); + app.privateInstanceCall(); + app.publicInstanceCall(); + Object a = app; ((Runnable)a).run(); ResolvedConstantsFoo foo = new ResolvedConstantsFoo(); @@ -101,6 +143,10 @@ public static void main(String args[]) { bar.b ++; bar.doit(); } + private static void staticCall() {} + private void privateInstanceCall() {} + public void publicInstanceCall() {} + public void run() {} } @@ -124,5 +170,7 @@ void doit() { System.out.println("b = " + b); doBar(this); + + ((ResolvedConstantsFoo)this).doBar(this); } } From 3b1ca986427d3a69c9e167b9b4c07d1b83bc264d Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Thu, 27 Jun 2024 20:27:51 +0000 Subject: [PATCH 14/85] 8334895: OpenJDK fails to configure on linux aarch64 when CDS is disabled after JDK-8331942 Reviewed-by: erikj --- make/autoconf/jdk-options.m4 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 0dca5d13313..54ead5ec1d7 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -197,9 +197,8 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], # three different page sizes: 4K, 64K, and if run on Mac m1 hardware, 16K. COMPATIBLE_CDS_ALIGNMENT_DEFAULT=false if test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then - COMPATIBLE_CDS_ALIGNMENT_DEFAULT=true + COMPATIBLE_CDS_ALIGNMENT_DEFAULT=auto fi - AC_SUBST(COMPATIBLE_CDS_ALIGNMENT_DEFAULT) # Compress jars COMPRESS_JARS=false @@ -672,7 +671,7 @@ AC_DEFUN([JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT], UTIL_ARG_ENABLE(NAME: compatible-cds-alignment, DEFAULT: $COMPATIBLE_CDS_ALIGNMENT_DEFAULT, RESULT: ENABLE_COMPATIBLE_CDS_ALIGNMENT, DESC: [enable use alternative compatible cds core region alignment], - DEFAULT_DESC: [disabled], + DEFAULT_DESC: [disabled except on linux-aarch64], CHECKING_MSG: [if compatible cds region alignment enabled], CHECK_AVAILABLE: [ AC_MSG_CHECKING([if CDS archive is available]) From 4e8cbf884ab1eee9c3110712ab62edc706e948ba Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 27 Jun 2024 22:20:14 +0000 Subject: [PATCH 15/85] 8335134: Test com/sun/jdi/BreakpointOnClassPrepare.java timeout Reviewed-by: kevinw, coleenp --- test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java index f4f1427e39b..deffffc0fa8 100644 --- a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java +++ b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java @@ -104,7 +104,15 @@ public static void main(String[] args) throws Exception { public void breakpointReached(BreakpointEvent event) { bkptCount++; - System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + event.thread()); + String threadInfo; + try { + threadInfo = event.thread().toString(); + } catch (ObjectCollectedException e) { + // It's possible the Thread already terminated and was collected + // if the SUSPEND_NONE policy was used. + threadInfo = "(thread collected)"; + } + System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + threadInfo); } public void vmDisconnected(VMDisconnectEvent event) { From cd46c87dc916b2b74067accf80c62df1792f74cf Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Fri, 28 Jun 2024 01:44:14 +0000 Subject: [PATCH 16/85] 8334843: RISC-V: Fix wraparound checking for r_array_index in lookup_secondary_supers_table_slow_path Reviewed-by: fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e889c26e5f4..0e6a9099265 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3799,7 +3799,7 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // Check for wraparound. Label skip; - bge(r_array_length, r_array_index, skip); + blt(r_array_index, r_array_length, skip); mv(r_array_index, zr); bind(skip); From b4df380f1a4587247a843fe28ae041265f7cfc29 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 28 Jun 2024 03:07:09 +0000 Subject: [PATCH 17/85] 8334763: --enable-asan: assert(_thread->is_in_live_stack((address)this)) failed: not on stack? Reviewed-by: kbarrett, stuefe, erikj --- make/autoconf/jdk-options.m4 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 54ead5ec1d7..76e95127f73 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -437,12 +437,23 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER], # It's harmless to be suppressed in clang as well. ASAN_CFLAGS="-fsanitize=address -Wno-stringop-truncation -fno-omit-frame-pointer -fno-common -DADDRESS_SANITIZER" ASAN_LDFLAGS="-fsanitize=address" + # detect_stack_use_after_return causes ASAN to offload stack-local + # variables to c-heap and therefore breaks assumptions in hotspot + # that rely on data (e.g. Marks) living in thread stacks. + if test "x$TOOLCHAIN_TYPE" = "xgcc"; then + ASAN_CFLAGS="$ASAN_CFLAGS --param asan-use-after-return=0" + fi + if test "x$TOOLCHAIN_TYPE" = "xclang"; then + ASAN_CFLAGS="$ASAN_CFLAGS -fsanitize-address-use-after-return=never" + fi elif test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then # -Oy- is equivalent to -fno-omit-frame-pointer in GCC/Clang. ASAN_CFLAGS="-fsanitize=address -Oy- -DADDRESS_SANITIZER" # MSVC produces a warning if you pass -fsanitize=address to the linker. It also complains $ if -DEBUG is not passed to the linker when building with ASan. ASAN_LDFLAGS="-debug" + # -fsanitize-address-use-after-return is off by default in MS Visual Studio 22 (19.37.32824). + # cl : Command line warning D9002 : ignoring unknown option '-fno-sanitize-address-use-after-return' fi JVM_CFLAGS="$JVM_CFLAGS $ASAN_CFLAGS" JVM_LDFLAGS="$JVM_LDFLAGS $ASAN_LDFLAGS" From 308a81238362c39f5b18e2ae8444c96420ef297a Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Fri, 28 Jun 2024 04:42:33 +0000 Subject: [PATCH 18/85] 8334645: Un-problemlist vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java Reviewed-by: thartmann, lmesnik --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 2 -- test/hotspot/jtreg/ProblemList-zgc.txt | 2 -- 2 files changed, 4 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index 4d5e985c0a6..db8182641ac 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -115,5 +115,3 @@ serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic- serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 - -vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java 8298991 linux-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index d7d600aad49..1afe56c99f8 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -46,5 +46,3 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 - -vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java 8298991 linux-x64 From c47a0e005e54551e42ee1ae33d7169417a5f86d4 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Fri, 28 Jun 2024 06:19:37 +0000 Subject: [PATCH 19/85] 8334147: Shenandoah: Avoid taking lock for disabled free set logging Reviewed-by: shade, ysr --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 5 +---- .../gc/shenandoah/shenandoahControlThread.cpp | 22 +++++++------------ .../share/gc/shenandoah/shenandoahFreeSet.cpp | 10 +++++++++ .../share/gc/shenandoah/shenandoahFreeSet.hpp | 6 ++++- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 44ccac467fe..aea0af24575 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -153,10 +153,7 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { // the space. This would be the last action if there is nothing to evacuate. entry_cleanup_early(); - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); - } + heap->free_set()->log_status_under_lock(); // Perform concurrent class unloading if (heap->unload_classes() && diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 4f711350844..e538ca02467 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -147,10 +147,7 @@ void ShenandoahControlThread::run_service() { heap->set_forced_counters_update(true); // If GC was requested, we better dump freeset data for performance debugging - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); - } + heap->free_set()->log_status_under_lock(); switch (mode) { case concurrent_normal: @@ -178,18 +175,15 @@ void ShenandoahControlThread::run_service() { // Report current free set state at the end of cycle, whether // it is a normal completion, or the abort. - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); + heap->free_set()->log_status_under_lock(); - // Notify Universe about new heap usage. This has implications for - // global soft refs policy, and we better report it every time heap - // usage goes down. - heap->update_capacity_and_used_at_gc(); + // Notify Universe about new heap usage. This has implications for + // global soft refs policy, and we better report it every time heap + // usage goes down. + heap->update_capacity_and_used_at_gc(); - // Signal that we have completed a visit to all live objects. - heap->record_whole_heap_examined_timestamp(); - } + // Signal that we have completed a visit to all live objects. + heap->record_whole_heap_examined_timestamp(); // Disable forced counters update, and update counters one more time // to capture the state at the end of GC session. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index c11d7e814e4..258dfe17b73 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1130,6 +1130,16 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve) { } } +void ShenandoahFreeSet::log_status_under_lock() { + // Must not be heap locked, it acquires heap lock only when log is enabled + shenandoah_assert_not_heaplocked(); + if (LogTarget(Info, gc, free)::is_enabled() + DEBUG_ONLY(|| LogTarget(Debug, gc, free)::is_enabled())) { + ShenandoahHeapLocker locker(_heap->lock()); + log_status(); + } +} + void ShenandoahFreeSet::log_status() { shenandoah_assert_heaplocked(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index e2852e5548c..e4789d48f80 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -318,6 +318,9 @@ class ShenandoahFreeSet : public CHeapObj { void finish_rebuild(size_t cset_regions); + // log status, assuming lock has already been acquired by the caller. + void log_status(); + public: ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions); @@ -340,7 +343,8 @@ class ShenandoahFreeSet : public CHeapObj { void move_regions_from_collector_to_mutator(size_t cset_regions); void recycle_trash(); - void log_status(); + // Acquire heap lock and log status, assuming heap lock is not acquired by the caller. + void log_status_under_lock(); inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } From d457609f700bbb1fed233f1a04501c995852e5ac Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 28 Jun 2024 06:43:32 +0000 Subject: [PATCH 20/85] 8319947: Recursive lightweight locking: s390x implementation Reviewed-by: aboldtch, lucy --- .../cpu/s390/c1_MacroAssembler_s390.cpp | 14 +- .../cpu/s390/c2_MacroAssembler_s390.cpp | 13 +- .../cpu/s390/c2_MacroAssembler_s390.hpp | 8 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 28 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 493 +++++++++++++++--- src/hotspot/cpu/s390/macroAssembler_s390.hpp | 6 +- src/hotspot/cpu/s390/s390.ad | 34 ++ src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 18 +- src/hotspot/cpu/s390/vm_version_s390.hpp | 2 + 9 files changed, 489 insertions(+), 127 deletions(-) diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index c35b0923297..13b08067821 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -67,9 +67,6 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox verify_oop(Roop, FILE_AND_LINE); - // Load object header. - z_lg(Rmark, Address(Roop, hdr_offset)); - // Save object being locked into the BasicObjectLock... z_stg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); @@ -85,6 +82,10 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox lightweight_lock(Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { NearLabel done; + + // Load object header. + z_lg(Rmark, Address(Roop, hdr_offset)); + // and mark it as unlocked. z_oill(Rmark, markWord::unlocked_value); // Save unlocked object header into the displaced header location on the stack. @@ -141,12 +142,7 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb verify_oop(Roop, FILE_AND_LINE); if (LockingMode == LM_LIGHTWEIGHT) { - const Register tmp = Z_R1_scratch; - z_lg(Rmark, Address(Roop, hdr_offset)); - z_lgr(tmp, Rmark); - z_nill(tmp, markWord::monitor_value); - branch_optimized(Assembler::bcondNotZero, slow_case); - lightweight_unlock(Roop, Rmark, tmp, slow_case); + lightweight_unlock(Roop, Rmark, Z_R1_scratch, slow_case); } else if (LockingMode == LM_LEGACY) { // Test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object. If the object header is not pointing to diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 62c1bd943b6..3641d82dabe 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,15 @@ #define BLOCK_COMMENT(str) block_comment(str) #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2) { + compiler_fast_lock_lightweight_object(obj, temp1, temp2); +} + + +void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2) { + compiler_fast_unlock_lightweight_object(obj, temp1, temp2); +} + //------------------------------------------------------ // Special String Intrinsics. Implementation //------------------------------------------------------ diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp index a502e41ee08..aecb483f0a6 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,10 @@ // C2_MacroAssembler contains high-level macros for C2 public: + // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in s390.ad file. + void fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2); + void fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2); + //------------------------------------------- // Special String Intrinsics Implementation. //------------------------------------------- diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index bc7996c270f..14bb98cea6a 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1005,9 +1005,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord header = obj->mark().set_unlocked(); - // Load markWord from object into header. - z_lg(header, hdr_offset, object); - if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, object); testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); @@ -1015,9 +1012,12 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(object, /* mark word */ header, tmp, slow_case); + lightweight_lock(object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + // Load markWord from object into header. + z_lg(header, hdr_offset, object); + // Set header to be (markWord of object | UNLOCK_VALUE). // This will not change anything if it was unlocked before. z_oill(header, markWord::unlocked_value); @@ -1153,26 +1153,8 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // If we still have a lightweight lock, unlock the object and be done. if (LockingMode == LM_LIGHTWEIGHT) { - // Check for non-symmetric locking. This is allowed by the spec and the interpreter - // must handle it. - - Register tmp = current_header; - - // First check for lock-stack underflow. - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondNotHigh, slow_case); - - // Then check if the top of the lock-stack matches the unlocked object. - z_aghi(tmp, -oopSize); - z_lg(tmp, Address(Z_thread, tmp)); - compare64_and_branch(tmp, object, Assembler::bcondNotEqual, slow_case); - - z_lg(header, Address(object, hdr_offset)); - z_lgr(tmp, header); - z_nill(tmp, markWord::monitor_value); - z_brne(slow_case); - lightweight_unlock(object, header, tmp, slow_case); + lightweight_unlock(object, header, current_header, slow_case); z_bru(done); } else { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 275f4a8d832..66d6f25f0fd 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3190,16 +3190,20 @@ void MacroAssembler::increment_counter_eq(address counter_address, Register tmp1 bind(l); } +// "The box" is the space on the stack where we copy the object mark. void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2) { + + assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_lock_lightweight"); + assert_different_registers(oop, box, temp1, temp2); + Register displacedHeader = temp1; - Register currentHeader = temp1; - Register temp = temp2; + Register currentHeader = temp1; + Register temp = temp2; + NearLabel done, object_has_monitor; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(temp1, temp2, oop, box); - BLOCK_COMMENT("compiler_fast_lock_object {"); // Load markWord from oop into mark. @@ -3207,8 +3211,10 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(temp, oop); - testbit(Address(temp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); - z_btrue(done); + z_l(temp, Address(temp, Klass::access_flags_offset())); + assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); + z_nilh(temp, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_brne(done); } // Handle existing monitor. @@ -3222,7 +3228,8 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // From loading the markWord, we know that oop != nullptr z_ltgr(oop, oop); z_bru(done); - } else if (LockingMode == LM_LEGACY) { + } else { + assert(LockingMode == LM_LEGACY, "must be"); // Set mark to markWord | markWord::unlocked_value. z_oill(displacedHeader, markWord::unlocked_value); @@ -3251,10 +3258,6 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis z_stg(currentHeader/*==0 or not 0*/, BasicLock::displaced_header_offset_in_bytes(), box); - z_bru(done); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - lightweight_lock(oop, displacedHeader, temp, done); z_bru(done); } @@ -3270,10 +3273,9 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // Otherwise, register zero is filled with the current owner. z_lghi(zero, 0); z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor_tagged); - if (LockingMode != LM_LIGHTWEIGHT) { - // Store a non-null value into the box. - z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); - } + + // Store a non-null value into the box. + z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); z_bre(done); // acquired the lock for the first time. @@ -3295,14 +3297,16 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis } void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2) { + + assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_unlock_lightweight"); + assert_different_registers(oop, box, temp1, temp2); + Register displacedHeader = temp1; - Register currentHeader = temp2; - Register temp = temp1; + Register currentHeader = temp2; + Register temp = temp1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(temp1, temp2, oop, box); - Label done, object_has_monitor, not_recursive; BLOCK_COMMENT("compiler_fast_unlock_object {"); @@ -3326,18 +3330,14 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // Set NE to indicate 'failure' -> take slow-path z_ltgr(oop, oop); z_bru(done); - } else if (LockingMode == LM_LEGACY) { + } else { + assert(LockingMode == LM_LEGACY, "must be"); // Check if it is still a lightweight lock, this is true if we see // the stack address of the basicLock in the markWord of the object // copy box to currentHeader such that csg does not kill it. z_lgr(currentHeader, box); z_csg(currentHeader, displacedHeader, hdr_offset, oop); z_bru(done); // csg sets CR as desired. - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - - lightweight_unlock(oop, currentHeader, displacedHeader, done); - z_bru(done); } // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0. @@ -5705,103 +5705,426 @@ SkipIfEqual::~SkipIfEqual() { } // Implements lightweight-locking. -// Branches to slow upon failure to lock the object. -// Falls through upon success. -// // - obj: the object to be locked, contents preserved. -// - hdr: the header, already loaded from obj, contents destroyed. +// - temp1, temp2: temporary registers, contents destroyed. // Note: make sure Z_R1 is not manipulated here when C2 compiler is in play -void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register temp, Label& slow_case) { +void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, temp); + assert_different_registers(obj, temp1, temp2); + + Label push; + const Register top = temp1; + const Register mark = temp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + // Preload the markWord. It is important that this is the first + // instruction emitted as it is part of C1's null check semantics. + z_lg(mark, Address(obj, mark_offset)); + // First we need to check if the lock-stack has room for pushing the object reference. - z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + z_lgf(top, Address(Z_thread, ls_top_offset)); - compareU32_and_branch(temp, (unsigned)LockStack::end_offset()-1, bcondHigh, slow_case); + compareU32_and_branch(top, (unsigned)LockStack::end_offset(), bcondNotLow, slow); - // attempting a lightweight_lock - // Load (object->mark() | 1) into hdr - z_oill(hdr, markWord::unlocked_value); + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. - z_lgr(temp, hdr); + // Check for recursion: + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(push); - // Clear lock-bits from hdr (locked state) - z_xilf(temp, markWord::unlocked_value); + // Check header for monitor (0b10). + z_tmll(mark, markWord::monitor_value); + branch_optimized(bcondNotAllZero, slow); - z_csg(hdr, temp, oopDesc::mark_offset_in_bytes(), obj); - branch_optimized(Assembler::bcondNotEqual, slow_case); + { // Try to lock. Transition lock bits 0b01 => 0b00 + const Register locked_obj = top; + z_oill(mark, markWord::unlocked_value); + z_lgr(locked_obj, mark); + // Clear lock-bits from locked_obj (locked state) + z_xilf(locked_obj, markWord::unlocked_value); + z_csg(mark, locked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondNotEqual, slow); + } - // After successful lock, push object on lock-stack - z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - z_stg(obj, Address(Z_thread, temp)); - z_ahi(temp, oopSize); - z_st(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + bind(push); - // as locking was successful, set CC to EQ - z_cr(temp, temp); + // After successful lock, push object on lock-stack + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_stg(obj, Address(Z_thread, top)); + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); } // Implements lightweight-unlocking. -// Branches to slow upon failure. -// Falls through upon success. -// // - obj: the object to be unlocked -// - hdr: the (pre-loaded) header of the object, will be destroyed +// - temp1, temp2: temporary registers, will be destroyed // - Z_R1_scratch: will be killed in case of Interpreter & C1 Compiler -void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, tmp); + assert_different_registers(obj, temp1, temp2); + + Label unlocked, push_and_slow; + const Register mark = temp1; + const Register top = temp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); #ifdef ASSERT - { - // Check that hdr is lightweight-locked. - Label hdr_ok; - z_lgr(tmp, hdr); - z_nill(tmp, markWord::lock_mask_in_place); - z_bre(hdr_ok); - stop("Header is not lightweight-locked"); - bind(hdr_ok); - } { // The following checks rely on the fact that LockStack is only ever modified by // its owning thread, even if the lock got inflated concurrently; removal of LockStack // entries after inflation will happen delayed in that case. // Check for lock-stack underflow. - Label stack_ok; - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondHigh, stack_ok); + NearLabel stack_ok; + z_lgf(top, Address(Z_thread, ls_top_offset)); + compareU32_and_branch(top, (unsigned)LockStack::start_offset(), bcondNotLow, stack_ok); stop("Lock-stack underflow"); bind(stack_ok); } - { - // Check if the top of the lock-stack matches the unlocked object. - Label tos_ok; - z_aghi(tmp, -oopSize); - z_lg(tmp, Address(Z_thread, tmp)); - compare64_and_branch(tmp, obj, Assembler::bcondEqual, tos_ok); - stop("Top of lock-stack does not match the unlocked object"); - bind(tos_ok); +#endif // ASSERT + + // Check if obj is top of lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondNotEqual, slow); + + // pop object from lock-stack +#ifdef ASSERT + const Register temp_top = temp1; // mark is not yet loaded, but be careful + z_agrk(temp_top, top, Z_thread); + z_xc(0, oopSize-1, temp_top, 0, temp_top); // wipe out lock-stack entry +#endif // ASSERT + z_alsi(in_bytes(ls_top_offset), Z_thread, -oopSize); // pop object + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. (this is a check for the 2nd object on the stack) + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondEqual, unlocked); + + // Not recursive. Check header for monitor (0b10). + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(push_and_slow); + +#ifdef ASSERT + // Check header not unlocked (0b01). + NearLabel not_unlocked; + z_tmll(mark, markWord::unlocked_value); + z_braz(not_unlocked); + stop("lightweight_unlock already unlocked"); + bind(not_unlocked); +#endif // ASSERT + + { // Try to unlock. Transition lock bits 0b00 => 0b01 + Register unlocked_obj = top; + z_lgr(unlocked_obj, mark); + z_oill(unlocked_obj, markWord::unlocked_value); + z_csg(mark, unlocked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondEqual, unlocked); + } + + bind(push_and_slow); + + // Restore lock-stack and handle the unlock in runtime. + z_lgf(top, Address(Z_thread, ls_top_offset)); + DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));) + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + // set CC to NE + z_ltgr(obj, obj); // object shouldn't be null at this point + branch_optimized(bcondAlways, slow); + + bind(unlocked); +} + +void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2) { + assert_different_registers(obj, tmp1, tmp2); + + // Handle inflated monitor. + NearLabel inflated; + // Finish fast lock successfully. MUST reach to with flag == NE + NearLabel locked; + // Finish fast lock unsuccessfully. MUST branch to with flag == EQ + NearLabel slow_path; + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp1, obj); + z_l(tmp1, Address(tmp1, Klass::access_flags_offset())); + assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); + z_nilh(tmp1, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_brne(slow_path); + } + + const Register mark = tmp1; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + BLOCK_COMMENT("compiler_fast_lightweight_locking {"); + { // lightweight locking + + // Push lock to the lock stack and finish successfully. MUST reach to with flag == EQ + NearLabel push; + + const Register top = tmp2; + + // Check if lock-stack is full. + z_lgf(top, Address(Z_thread, ls_top_offset)); + compareU32_and_branch(top, (unsigned) LockStack::end_offset() - 1, bcondHigh, slow_path); + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(push); + + // Check for monitor (0b10) + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + + // not inflated + + { // Try to lock. Transition lock bits 0b01 => 0b00 + assert(mark_offset == 0, "required to avoid a lea"); + const Register locked_obj = top; + z_oill(mark, markWord::unlocked_value); + z_lgr(locked_obj, mark); + // Clear lock-bits from locked_obj (locked state) + z_xilf(locked_obj, markWord::unlocked_value); + z_csg(mark, locked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondNotEqual, slow_path); + } + + bind(push); + + // After successful lock, push object on lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_stg(obj, Address(Z_thread, top)); + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + + z_cgr(obj, obj); // set the CC to EQ, as it could be changed by alsi + z_bru(locked); + } + BLOCK_COMMENT("} compiler_fast_lightweight_locking"); + + BLOCK_COMMENT("handle_inflated_monitor_lightweight_locking {"); + { // Handle inflated monitor. + bind(inflated); + + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); + z_bre(locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); + z_cgr(zero, zero); + // z_bru(locked); + // Uncomment above line in the future, for now jump address is right next to us. } + BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); + + bind(locked); + +#ifdef ASSERT + // Check that locked label is reached with flag == EQ. + NearLabel flag_correct; + z_bre(flag_correct); + stop("CC is not set to EQ, it should be - lock"); +#endif // ASSERT + + bind(slow_path); + +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + z_brne(flag_correct); + stop("CC is not set to NE, it should be - lock"); + bind(flag_correct); #endif // ASSERT - z_lgr(tmp, hdr); - z_oill(tmp, markWord::unlocked_value); - z_csg(hdr, tmp, oopDesc::mark_offset_in_bytes(), obj); - branch_optimized(Assembler::bcondNotEqual, slow); + // C2 uses the value of flag (NE vs EQ) to determine the continuation. +} + +void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2) { + assert_different_registers(obj, tmp1, tmp2); - // After successful unlock, pop object from lock-stack + // Handle inflated monitor. + NearLabel inflated, inflated_load_monitor; + // Finish fast unlock successfully. MUST reach to with flag == EQ. + NearLabel unlocked; + // Finish fast unlock unsuccessfully. MUST branch to with flag == NE. + NearLabel slow_path; + + const Register mark = tmp1; + const Register top = tmp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + BLOCK_COMMENT("compiler_fast_lightweight_unlock {"); + { // Lightweight Unlock + + // Check if obj is top of lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondNotEqual, inflated_load_monitor); + + // Pop lock-stack. #ifdef ASSERT - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - z_aghi(tmp, -oopSize); - z_agr(tmp, Z_thread); - z_xc(0, oopSize-1, tmp, 0, tmp); // wipe out lock-stack entry + const Register temp_top = tmp1; // let's not kill top here, we can use for recursive check + z_agrk(temp_top, top, Z_thread); + z_xc(0, oopSize-1, temp_top, 0, temp_top); // wipe out lock-stack entry #endif - z_alsi(in_bytes(JavaThread::lock_stack_top_offset()), Z_thread, -oopSize); // pop object - z_cr(tmp, tmp); // set CC to EQ + z_alsi(in_bytes(ls_top_offset), Z_thread, -oopSize); // pop object + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(unlocked); + + // Not recursive + + // Check for monitor (0b10). + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + +#ifdef ASSERT + // Check header not unlocked (0b01). + NearLabel not_unlocked; + z_tmll(mark, markWord::unlocked_value); + z_braz(not_unlocked); + stop("lightweight_unlock already unlocked"); + bind(not_unlocked); +#endif // ASSERT + + { // Try to unlock. Transition lock bits 0b00 => 0b01 + Register unlocked_obj = top; + z_lgr(unlocked_obj, mark); + z_oill(unlocked_obj, markWord::unlocked_value); + z_csg(mark, unlocked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondEqual, unlocked); + } + + // Restore lock-stack and handle the unlock in runtime. + z_lgf(top, Address(Z_thread, ls_top_offset)); + DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));) + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + // set CC to NE + z_ltgr(obj, obj); // object is not null here + z_bru(slow_path); + } + BLOCK_COMMENT("} compiler_fast_lightweight_unlock"); + + { // Handle inflated monitor. + + bind(inflated_load_monitor); + + z_lg(mark, Address(obj, mark_offset)); + +#ifdef ASSERT + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + stop("Fast Unlock not monitor"); +#endif // ASSERT + + bind(inflated); + +#ifdef ASSERT + NearLabel check_done, loop; + z_lgf(top, Address(Z_thread, ls_top_offset)); + bind(loop); + z_aghi(top, -oopSize); + compareU32_and_branch(top, in_bytes(JavaThread::lock_stack_base_offset()), + bcondLow, check_done); + z_cg(obj, Address(Z_thread, top)); + z_brne(loop); + stop("Fast Unlock lock on stack"); + bind(check_done); +#endif // ASSERT + + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + + NearLabel not_recursive; + const Register recursions = tmp2; + + // Check if recursive. + load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking + + // Recursive unlock + z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); + + bind(not_recursive); + + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + z_brne(not_ok); + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + z_brne(not_ok); + + z_release(); + z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + + z_bru(unlocked); // CC = EQ here + + bind(not_ok); + + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_bru(slow_path); // CC = NE here + } + + bind(unlocked); + +#ifdef ASSERT + // Check that unlocked label is reached with flag == EQ. + NearLabel flag_correct; + z_bre(flag_correct); + stop("CC is not set to EQ, it should be - unlock"); +#endif // ASSERT + + bind(slow_path); + +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + z_brne(flag_correct); + stop("CC is not set to NE, it should be - unlock"); + bind(flag_correct); +#endif // ASSERT + + // C2 uses the value of flag (NE vs EQ) to determine the continuation. } void MacroAssembler::pop_count_int(Register r_dst, Register r_src, Register r_tmp) { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 9f45542dd65..684741d79db 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -727,8 +727,10 @@ class MacroAssembler: public Assembler { void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2); void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2); - void lightweight_lock(Register obj, Register hdr, Register tmp, Label& slow); - void lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow); + void lightweight_lock(Register obj, Register tmp1, Register tmp2, Label& slow); + void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Label& slow); + void compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2); + void compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2); void resolve_jobject(Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 56cf494d27e..0fe3840b9b5 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -9579,6 +9579,7 @@ instruct partialSubtypeCheck_vs_zero(flagsReg pcc, rarg2RegP sub, rarg3RegP supe // inlined locking and unlocking instruct cmpFastLock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set pcc (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2); ins_cost(100); @@ -9589,6 +9590,7 @@ instruct cmpFastLock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRe %} instruct cmpFastUnlock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set pcc (FastUnlock oop box)); effect(TEMP tmp1, TEMP tmp2); ins_cost(100); @@ -9598,6 +9600,38 @@ instruct cmpFastUnlock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, i ins_pipe(pipe_class_dummy); %} +instruct cmpFastLockLightweight(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set pcc (FastLock oop box)); + effect(TEMP tmp1, TEMP tmp2); + ins_cost(100); + // TODO: s390 port size(VARIABLE_SIZE); + format %{ "FASTLOCK $oop, $box; KILL Z_ARG4, Z_ARG5" %} + ins_encode %{ + __ fast_lock_lightweight($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); + // If locking was successful, cc should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_locking_Java for the case where cc is 'NE'. + %} + ins_pipe(pipe_class_dummy); +%} + +instruct cmpFastUnlockLightweight(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set pcc (FastUnlock oop box)); + effect(TEMP tmp1, TEMP tmp2); + ins_cost(100); + // TODO: s390 port size(FIXED_SIZE); + format %{ "FASTUNLOCK $oop, $box; KILL Z_ARG4, Z_ARG5" %} + ins_encode %{ + __ fast_unlock_lightweight($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); + // If unlocking was successful, cc should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_unlocking_Java for the case where cc is 'NE'. + %} + ins_pipe(pipe_class_dummy); +%} + instruct inlineCallClearArrayConst(SSlenDW cnt, iRegP_N2P base, Universe dummy, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); effect(KILL cr); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 87cf9cb600c..0ee88345282 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1711,8 +1711,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for locking. - // Fast_lock kills r_temp_1, r_temp_2. - __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); + if (LockingMode == LM_LIGHTWEIGHT) { + // Fast_lock kills r_temp_1, r_temp_2. + __ compiler_fast_lock_lightweight_object(r_oop, r_tmp1, r_tmp2); + } else { + // Fast_lock kills r_temp_1, r_temp_2. + __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); + } __ z_bre(done); //------------------------------------------------------------------------- @@ -1910,8 +1915,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for unlocking. - // Fast_unlock kills r_tmp1, r_tmp2. - __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); + if (LockingMode == LM_LIGHTWEIGHT) { + // Fast_unlock kills r_tmp1, r_tmp2. + __ compiler_fast_unlock_lightweight_object(r_oop, r_tmp1, r_tmp2); + } else { + // Fast_unlock kills r_tmp1, r_tmp2. + __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); + } __ z_bre(done); // Slow path for unlocking. diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 7ac60a10ae7..4f963c4e485 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -413,6 +413,8 @@ class VM_Version: public Abstract_VM_Version { // s390 supports fast class initialization checks static bool supports_fast_class_init_checks() { return true; } + constexpr static bool supports_recursive_lightweight_locking() { return true; } + // CPU feature query functions static const char* get_model_string() { return _model_string; } static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; } From 3b3a19e907c7267f03c0b07312b929b7b4b6d200 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 28 Jun 2024 08:27:07 +0000 Subject: [PATCH 21/85] 8335314: Problem list compiler/uncommontrap/DeoptReallocFailure.java Reviewed-by: chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 254e621bfdd..febde61c4fd 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -70,6 +70,8 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all +compiler/uncommontrap/DeoptReallocFailure.java 8335308 windows-x64 + ############################################################################# # :hotspot_gc From 6f4ddc2f6bf0dd9a626a76d0f5e56a54c6cf6b65 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 28 Jun 2024 09:23:48 +0000 Subject: [PATCH 22/85] 8335142: compiler/c1/TestTraceLinearScanLevel.java occasionally times out with -Xcomp Reviewed-by: thartmann, kvn --- test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java b/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java index 2e4ec32869d..46a294388e6 100644 --- a/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java +++ b/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java @@ -26,8 +26,8 @@ * @bug 8251093 * @summary Sanity check the flag TraceLinearScanLevel with the highest level in a silent HelloWorld program. * - * @requires vm.debug == true & vm.compiler1.enabled - * @run main/othervm -XX:TraceLinearScanLevel=4 compiler.c1.TestTraceLinearScanLevel + * @requires vm.debug == true & vm.compiler1.enabled & vm.compMode != "Xcomp" + * @run main/othervm -Xbatch -XX:TraceLinearScanLevel=4 compiler.c1.TestTraceLinearScanLevel */ package compiler.c1; From 99d2bbf767ac33e1a021c90ba12d95ef37ea4816 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 28 Jun 2024 09:31:14 +0000 Subject: [PATCH 23/85] 8334433: jshell.exe runs an executable test.exe on startup Reviewed-by: jpai --- .../jdk/internal/org/jline/utils/OSUtils.java | 2 +- .../jshell/tool/ConsoleIOContext.java | 7 +- .../jdk/jshell/TerminalNoExecTest.java | 96 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/langtools/jdk/jshell/TerminalNoExecTest.java diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java index 344d081c124..7fdfb9a028f 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java @@ -63,7 +63,7 @@ private static boolean isExecutable(File f) { String sttyfopt = null; String infocmp = null; String test = null; - String path = System.getenv("PATH"); + String path = "/usr/bin" + File.pathSeparator + "/bin";//was: System.getenv("PATH"); if (path != null) { String[] paths = path.split(File.pathSeparator); for (String p : paths) { diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index a2b1ca0d2d0..f4ca58d6af4 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -154,7 +154,12 @@ public int readBuffered(byte[] b) throws IOException { setupReader = setupReader.andThen(r -> r.option(Option.DISABLE_HIGHLIGHTER, !enableHighlighter)); input.setInputStream(cmdin); } else { - terminal = TerminalBuilder.builder().inputStreamWrapper(in -> { + //on platforms which are known to be fully supported by + //the FFMTerminalProvider, do not permit the ExecTerminalProvider: + boolean allowExecTerminal = !OSUtils.IS_WINDOWS && + !OSUtils.IS_LINUX && + !OSUtils.IS_OSX; + terminal = TerminalBuilder.builder().exec(allowExecTerminal).inputStreamWrapper(in -> { input.setInputStream(in); return nonBlockingInput; }).nativeSignals(false).build(); diff --git a/test/langtools/jdk/jshell/TerminalNoExecTest.java b/test/langtools/jdk/jshell/TerminalNoExecTest.java new file mode 100644 index 00000000000..3d76157fd26 --- /dev/null +++ b/test/langtools/jdk/jshell/TerminalNoExecTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8334433 + * @summary Verify that when running JShell on platforms that support FFMTerminalProvider, + * no new processes are spawned. + * @requires os.family == "windows" | os.family == "mac" | os.family == "linux" + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavaTask TerminalNoExecTest + * @run main TerminalNoExecTest + */ + +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import jdk.jfr.consumer.RecordingStream; +import jdk.jshell.tool.JavaShellToolBuilder; + +import toolbox.ToolBox; + +public class TerminalNoExecTest { + + public static void main(String... args) throws Exception { + if (args.length > 0) { + AtomicBoolean spawnedNewProcess = new AtomicBoolean(); + try (var rs = new RecordingStream()) { + rs.enable("jdk.ProcessStart").withoutThreshold(); + rs.onEvent(evt -> { + System.err.println("evt: " + evt); + spawnedNewProcess.set(true); + }); + rs.startAsync(); + JavaShellToolBuilder.builder().run("--execution=local", "--no-startup"); + rs.stop(); + } + if (spawnedNewProcess.get()) { + System.err.println("Spawned a new process!"); + System.exit(1); + } + System.exit(0); + } else { + Path testScript = Paths.get("do-exit"); + try (Writer w = Files.newBufferedWriter(testScript)) { + w.append("/exit\n"); + } + + ToolBox tb = new ToolBox(); + Process target = + new ProcessBuilder(tb.getJDKTool("java").toString(), + "-classpath", System.getProperty("java.class.path"), + TerminalNoExecTest.class.getName(), + "run-test") + .redirectError(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectInput(testScript.toFile()) + .start(); + + target.waitFor(); + + int exitCode = target.exitValue(); + + if (exitCode != 0) { + throw new AssertionError("Incorrect exit value, expected 0, got: " + exitCode); + } + } + } + +} From c798316bc4cb33fd902f926030d8a0b6870d661a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 28 Jun 2024 09:38:18 +0000 Subject: [PATCH 24/85] 8269657: Test java/nio/channels/DatagramChannel/Loopback.java failed: Unexpected message Reviewed-by: dfuchs --- .../nio/channels/DatagramChannel/Loopback.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java index a61a4d0b177..5562378b83f 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,8 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) // send datagram to multicast group System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); - ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8")); + String str = "hello " + System.nanoTime(); + ByteBuffer src = ByteBuffer.wrap(str.getBytes("UTF-8")); dc.send(src, target); // receive datagram sent to multicast group @@ -142,6 +143,7 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); src.clear(); dc.send(src, target); + src.flip(); // test that we don't receive the datagram sent to multicast group dc.configureBlocking(false); @@ -157,10 +159,16 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) } else { sel.selectedKeys().clear(); SocketAddress sender = dc.receive(dst); + if (src.mismatch(dst) != -1) { + System.out.println("src: " + src + "not equal to dst: " + dst); + dst.clear(); + continue; + } if (sender != null) { System.out.format("received %s from %s%n", dst, sender); senderPort = ((InetSocketAddress) sender).getPort(); - assertTrue(senderPort != localPort, "Unexpected message"); + assertTrue(senderPort != localPort, + "Unexpected message: localPort=" + localPort); } } } From 8ec378a6c8a460dd0727df800419b3cf45d3c57a Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 28 Jun 2024 11:03:29 +0000 Subject: [PATCH 25/85] 8277949: (dc) java/nio/channels/DatagramChannel/AdaptorBasic.java failed in timeout Reviewed-by: jpai --- .../DatagramChannel/AdaptorBasic.java | 40 ++++++++++++++++--- test/jdk/java/nio/channels/TestServers.java | 31 ++++++++++++-- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java index 4ac5d4b3c88..504b648dcb6 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,8 @@ import java.util.*; import java.lang.reflect.Field; +import jdk.test.lib.Platform; + public class AdaptorBasic { @@ -69,6 +71,8 @@ static void test(DatagramSocket ds, InetSocketAddress dst, boolean shouldTimeout for (;;) { try { ds.receive(ip); + // weed off stray datagrams + if (ip.getPort() != dst.getPort()) continue; } catch (SocketTimeoutException x) { if (shouldTimeout) { out.println("Receive timed out, as expected"); @@ -111,12 +115,36 @@ static void test(InetSocketAddress dst, // Original ds = new DatagramSocket(); } else { - DatagramChannel dc = DatagramChannel.open(); - ds = dc.socket(); - ds.bind(new InetSocketAddress(0)); + int attempts = 0; + DatagramChannel toclose = null; + while (true) { + DatagramChannel dc = DatagramChannel.open(); + ds = dc.socket(); + if (Platform.isOSX() && dst.getAddress().isLoopbackAddress()) { + // avoid binding to the wildcard on macOS if possible, in order to limit + // potential port conflict issues + ds.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } else { + ds.bind(new InetSocketAddress(0)); + } + // on some systems it may be possible to bind two sockets + // to the same port if one of them is bound to the wildcard, + // if that happens, try again... + if (ds.getLocalPort() == dst.getPort()) { + if (toclose != null) toclose.close(); + toclose = dc; + if (++attempts == 10) { + throw new AssertionError("Couldn't allocate port for client socket"); + } + continue; + } + if (toclose != null) toclose.close(); + break; + } } - out.println("socket: " + ds); + out.println("socket: " + ds + " bound to src: " + + ds.getLocalSocketAddress() + ", dst: " + dst); if (connect) { ds.connect(dst); out.println("connect: " + ds); @@ -141,7 +169,7 @@ static void test(InetSocketAddress dst, public static void main(String[] args) throws Exception { // need an UDP echo server try (TestServers.UdpEchoServer echoServer - = TestServers.UdpEchoServer.startNewServer(100)) { + = TestServers.UdpEchoServer.startNewServer(100, InetAddress.getLoopbackAddress())) { final InetSocketAddress address = new InetSocketAddress(echoServer.getAddress(), echoServer.getPort()); diff --git a/test/jdk/java/nio/channels/TestServers.java b/test/jdk/java/nio/channels/TestServers.java index e2c4151195d..4f459c439f5 100644 --- a/test/jdk/java/nio/channels/TestServers.java +++ b/test/jdk/java/nio/channels/TestServers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -497,6 +497,7 @@ static abstract class AbstractUdpServer extends AbstractServer implements Runnable, Closeable { protected final long linger; // #of ms to wait before responding + protected final InetAddress bindAddress; //local address to bind to; can be null. private Thread acceptThread; // thread waiting for packets private DatagramSocket serverSocket; // the server socket private boolean started = false; // whether the server is started @@ -509,7 +510,20 @@ static abstract class AbstractUdpServer extends AbstractServer * responding to requests. */ protected AbstractUdpServer(long linger) { + this(linger, null); + } + + /** + * Creates a new abstract UDP server. + * + * @param linger the amount of time the server should wait before + * responding to requests. + * @param bindAddress the address to bind to. If {@code null}, will + * bind to InetAddress.getLocalHost(); + */ + protected AbstractUdpServer(long linger, InetAddress bindAddress) { this.linger = linger; + this.bindAddress = bindAddress; } /** @@ -574,8 +588,9 @@ public final synchronized void start() throws IOException { if (started) { return; } + InetAddress lh = bindAddress == null ? InetAddress.getLocalHost() : bindAddress; final DatagramSocket socket = - newDatagramSocket(0, InetAddress.getLocalHost()); + newDatagramSocket(0, lh); serverSocket = socket; acceptThread = new Thread(this); acceptThread.setDaemon(true); @@ -759,7 +774,11 @@ public UdpEchoServer() { } public UdpEchoServer(long linger) { - super(linger); + this(linger, null); + } + + public UdpEchoServer(long linger, InetAddress bindAddress) { + super(linger, bindAddress); } @Override @@ -795,7 +814,11 @@ public static UdpEchoServer startNewServer() throws IOException { } public static UdpEchoServer startNewServer(long linger) throws IOException { - final UdpEchoServer echoServer = new UdpEchoServer(linger); + return startNewServer(0, InetAddress.getLocalHost()); + } + + public static UdpEchoServer startNewServer(long linger, InetAddress bindAddress) throws IOException { + final UdpEchoServer echoServer = new UdpEchoServer(linger, bindAddress); echoServer.start(); return echoServer; } From 49eb00da8dc66cff3ca430f06ab21357ee6180ef Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 28 Jun 2024 11:13:11 +0000 Subject: [PATCH 26/85] 8299813: java/nio/channels/DatagramChannel/Disconnect.java fails with jtreg test timeout due to lost datagram Reviewed-by: aefimov --- .../channels/DatagramChannel/Disconnect.java | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java index 1ba742b6552..cdc5882fefd 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.nio.*; import java.nio.channels.*; import java.io.IOException; + import jdk.test.lib.net.IPSupport; public class Disconnect { @@ -42,43 +43,61 @@ public static void main(String[] args) throws IOException { // test with default protocol family try (DatagramChannel dc = DatagramChannel.open()) { - test(dc); - test(dc); + InetAddress lo = InetAddress.getLoopbackAddress(); + System.out.println("Testing with default family and " + lo); + test(dc, lo); + test(dc, lo); } if (IPSupport.hasIPv4()) { // test with IPv4 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - test(dc); - test(dc); + InetAddress lo4 = InetAddress.ofLiteral("127.0.0.1"); + System.out.println("Testing with INET family and " + lo4); + test(dc, lo4); + test(dc, lo4); } } if (IPSupport.hasIPv6()) { // test with IPv6 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { - test(dc); - test(dc); + InetAddress lo6 = InetAddress.ofLiteral("::1"); + System.out.println("Testing with INET6 family and " + lo6); + test(dc, lo6); + test(dc, lo6); } } } + static int getLocalPort(DatagramChannel ch) throws IOException { + return ((InetSocketAddress) ch.getLocalAddress()).getPort(); + } + /** * Connect DatagramChannel to a server, write a datagram and disconnect. Invoke * a second or subsequent time with the same DatagramChannel instance to check * that disconnect works as expected. */ - static void test(DatagramChannel dc) throws IOException { + static void test(DatagramChannel dc, InetAddress lo) throws IOException { try (DatagramChannel server = DatagramChannel.open()) { - server.bind(new InetSocketAddress(0)); + server.bind(new InetSocketAddress(lo, 0)); - InetAddress lh = InetAddress.getLocalHost(); - dc.connect(new InetSocketAddress(lh, server.socket().getLocalPort())); + SocketAddress dcbound = dc.getLocalAddress(); + dc.connect(new InetSocketAddress(lo, server.socket().getLocalPort())); + System.out.println("dc bound to " + dcbound + " and connected from " + + dc.getLocalAddress() + " to " + dc.getRemoteAddress()); dc.write(ByteBuffer.wrap("hello".getBytes())); - ByteBuffer bb = ByteBuffer.allocate(100); - server.receive(bb); + if (getLocalPort(dc) != getLocalPort(server)) { + ByteBuffer bb = ByteBuffer.allocate(100); + server.receive(bb); + } else { + // some systems may allow dc and server to bind to the same port. + // when that happen the datagram may never be received + System.out.println("Server and clients are bound to the same port: skipping receive"); + } dc.disconnect(); From f4d8c005b35ce34c96027b7f3abb7a307bca3f4c Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 28 Jun 2024 12:45:26 +0000 Subject: [PATCH 27/85] 8334562: Automate com/sun/security/auth/callback/TextCallbackHandler/Default.java test Reviewed-by: weijun --- test/jdk/ProblemList.txt | 1 - test/jdk/TEST.groups | 1 - .../callback/TextCallbackHandler/Default.java | 55 +++-- .../testlibrary/HumanInputStream.java | 192 ++++++++++++++++++ .../security/tools/keytool/KeyToolTest.java | 173 +--------------- 5 files changed, 231 insertions(+), 191 deletions(-) create mode 100644 test/jdk/java/security/testlibrary/HumanInputStream.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 790b3de0f96..20dfcef539d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -609,7 +609,6 @@ sun/security/smartcardio/TestMultiplePresent.java 8039280 generic- sun/security/smartcardio/TestPresent.java 8039280 generic-all sun/security/smartcardio/TestTransmit.java 8039280 generic-all com/sun/crypto/provider/Cipher/DES/PerformanceTest.java 8039280 generic-all -com/sun/security/auth/callback/TextCallbackHandler/Default.java 8039280 generic-all com/sun/security/auth/callback/TextCallbackHandler/Password.java 8039280 generic-all com/sun/security/sasl/gsskerb/AuthOnly.java 8039280 generic-all com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic-all diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 0a8d2748465..6a5be3736e8 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -624,7 +624,6 @@ jdk_security_manual_no_input = \ com/sun/crypto/provider/Cipher/DES/PerformanceTest.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ - com/sun/security/auth/callback/TextCallbackHandler/Default.java \ com/sun/security/auth/callback/TextCallbackHandler/Password.java \ com/sun/security/sasl/gsskerb/AuthOnly.java \ com/sun/security/sasl/gsskerb/ConfSecurityLayer.java \ diff --git a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java index 606a1ad5e0e..1fb3350c8f7 100644 --- a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java +++ b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,31 +23,48 @@ /* * @test + * @library /test/lib /java/security/testlibrary * @bug 4470717 * @summary fix default handling and other misc - * @run main/manual Default + * @run main/othervm Default */ import com.sun.security.auth.callback.TextCallbackHandler; +import jdk.test.lib.Asserts; + import javax.security.auth.callback.*; +import java.io.*; public class Default { - public static void main(String args[]) throws Exception { - TextCallbackHandler h = new TextCallbackHandler(); - NameCallback nc = new NameCallback("Name: ", "charlie"); - ConfirmationCallback cc = new ConfirmationCallback - ("Correct?", - ConfirmationCallback.INFORMATION, - ConfirmationCallback.YES_NO_OPTION, - ConfirmationCallback.NO); - - Callback[] callbacks = { nc, cc }; - h.handle(callbacks); - - if (cc.getSelectedIndex() == ConfirmationCallback.YES) { - System.out.println("yes"); - } else { - System.out.println("no"); + public static void main(String args[]) throws Exception { + InputStream in = System.in; + PrintStream err = System.err; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final String defaultName = "charlie"; + final String simulatedInput = "-1\n-1\n"; + HumanInputStream humanInputStream = new HumanInputStream(simulatedInput); + + try (PrintStream prints = new PrintStream(baos)) { + System.setIn(humanInputStream); + System.setErr(prints); + NameCallback nameCallback = new NameCallback("Name: ", defaultName); + ConfirmationCallback confirmationCallback = new ConfirmationCallback( + "Correct?", + ConfirmationCallback.INFORMATION, + ConfirmationCallback.YES_NO_OPTION, + ConfirmationCallback.NO); + new TextCallbackHandler().handle(new Callback[]{nameCallback, confirmationCallback}); + + Asserts.assertEquals(nameCallback.getDefaultName(), defaultName); + Asserts.assertEquals(confirmationCallback.getSelectedIndex(), ConfirmationCallback.NO); + + } finally { + System.setIn(in); + System.setErr(err); } - } + + // check that the default name and confirmation were visible in the output + Asserts.assertTrue(baos.toString().contains(String.format("Name: [%s]", defaultName))); + Asserts.assertTrue(baos.toString().contains("1. No [default]")); + } } diff --git a/test/jdk/java/security/testlibrary/HumanInputStream.java b/test/jdk/java/security/testlibrary/HumanInputStream.java new file mode 100644 index 00000000000..50e5dd0bcc8 --- /dev/null +++ b/test/jdk/java/security/testlibrary/HumanInputStream.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * HumanInputStream tries to act like a human sitting in front of a computer + * terminal typing on the keyboard while a program is running. + *

+ * The program may call InputStream.read() and BufferedReader.readLine() in + * various places. a call to B.readLine() will try to buffer as much input as + * possible. Thus, a trivial InputStream will find it impossible to feed + * anything to I.read() after a B.readLine() call. + *

+ * This is why HumanInputStream was created, which will only send a single line + * to B.readLine(), no more, no less, and the next I.read() can have a chance + * to read the exact character right after "\n". + * + */ + +public class HumanInputStream extends InputStream { + byte[] src; + int pos; + int length; + boolean inLine; + int stopIt; + + public HumanInputStream(String input) { + src = input.getBytes(); + pos = 0; + length = src.length; + stopIt = 0; + inLine = false; + } + + // the trick: when called through read(byte[], int, int), + // return -1 twice after "\n" + + @Override public int read() throws IOException { + int re; + if(pos < length) { + re = src[pos]; + if(inLine) { + if(stopIt > 0) { + stopIt--; + re = -1; + } else { + if(re == '\n') { + stopIt = 2; + } + pos++; + } + } else { + pos++; + } + } else { + re = -1; //throws new IOException("NO MORE TO READ"); + } + return re; + } + @Override public int read(byte[] buffer, int offset, int len) { + inLine = true; + try { + return super.read(buffer, offset, len); + } catch(Exception e) { + throw new RuntimeException("HumanInputStream error"); + } finally { + inLine = false; + } + } + @Override public int available() { + if (pos < length) return 1; + return 0; + } + + // test part + static void assertTrue(boolean bool) { + if (!bool) + throw new RuntimeException(); + } + + public static void test() throws Exception { + class Tester { + HumanInputStream is; + BufferedReader reader; + Tester(String s) { + is = new HumanInputStream(s); + reader = new BufferedReader(new InputStreamReader(is)); + } + + // three kinds of test method + // 1. read byte by byte from InputStream + void testStreamReadOnce(int expection) throws Exception { + assertTrue(is.read() == expection); + } + void testStreamReadMany(String expectation) throws Exception { + char[] keys = expectation.toCharArray(); + for (char key : keys) { + assertTrue(is.read() == key); + } + } + // 2. read a line with a newly created Reader + void testReaderReadline(String expectation) throws Exception { + String s = new BufferedReader(new InputStreamReader(is)).readLine(); + if(s == null) assertTrue(expectation == null); + else assertTrue(s.equals(expectation)); + } + // 3. read a line with the old Reader + void testReaderReadline2(String expectation) throws Exception { + String s = reader.readLine(); + if(s == null) assertTrue(expectation == null); + else assertTrue(s.equals(expectation)); + } + } + + Tester test; + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline("111"); + test.testReaderReadline("222"); + test.testReaderReadline(""); + test.testReaderReadline("444"); + test.testReaderReadline(""); + test.testReaderReadline(null); + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline2("111"); + test.testReaderReadline2("222"); + test.testReaderReadline2(""); + test.testReaderReadline2("444"); + test.testReaderReadline2(""); + test.testReaderReadline2(null); + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline2("111"); + test.testReaderReadline("222"); + test.testReaderReadline2(""); + test.testReaderReadline2("444"); + test.testReaderReadline(""); + test.testReaderReadline2(null); + + test = new Tester("1\n2"); + test.testStreamReadMany("1\n2"); + test.testStreamReadOnce(-1); + + test = new Tester("12\n234"); + test.testStreamReadOnce('1'); + test.testReaderReadline("2"); + test.testStreamReadOnce('2'); + test.testReaderReadline2("34"); + test.testReaderReadline2(null); + + test = new Tester("changeit\n"); + test.testStreamReadMany("changeit\n"); + test.testReaderReadline(null); + + test = new Tester("changeit\nName\nCountry\nYes\n"); + test.testStreamReadMany("changeit\n"); + test.testReaderReadline("Name"); + test.testReaderReadline("Country"); + test.testReaderReadline("Yes"); + test.testReaderReadline(null); + + test = new Tester("Me\nHere\n"); + test.testReaderReadline2("Me"); + test.testReaderReadline2("Here"); + } +} diff --git a/test/jdk/sun/security/tools/keytool/KeyToolTest.java b/test/jdk/sun/security/tools/keytool/KeyToolTest.java index b17f7b7d999..7b5f4d5556e 100644 --- a/test/jdk/sun/security/tools/keytool/KeyToolTest.java +++ b/test/jdk/sun/security/tools/keytool/KeyToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @library /java/security/testlibrary * @bug 6251120 8231950 8242151 * @summary Testing keytool * @@ -1865,172 +1866,4 @@ class TestException extends Exception { public TestException(String e) { super(e); } -} - -/** - * HumanInputStream tries to act like a human sitting in front of a computer - * terminal typing on the keyboard while the keytool program is running. - * - * keytool has called InputStream.read() and BufferedReader.readLine() in - * various places. a call to B.readLine() will try to buffer as much input as - * possible. Thus, a trivial InputStream will find it impossible to feed - * anything to I.read() after a B.readLine() call. - * - * This is why i create HumanInputStream, which will only send a single line - * to B.readLine(), no more, no less, and the next I.read() can have a chance - * to read the exact character right after "\n". - * - * I don't know why HumanInputStream works. - */ -class HumanInputStream extends InputStream { - byte[] src; - int pos; - int length; - boolean inLine; - int stopIt; - - public HumanInputStream(String input) { - src = input.getBytes(); - pos = 0; - length = src.length; - stopIt = 0; - inLine = false; - } - - // the trick: when called through read(byte[], int, int), - // return -1 twice after "\n" - - @Override public int read() throws IOException { - int re; - if(pos < length) { - re = src[pos]; - if(inLine) { - if(stopIt > 0) { - stopIt--; - re = -1; - } else { - if(re == '\n') { - stopIt = 2; - } - pos++; - } - } else { - pos++; - } - } else { - re = -1;//throw new IOException("NO MORE TO READ"); - } - //if (re < 32) System.err.printf("[%02d]", re); - //else System.err.printf("[%c]", (char)re); - return re; - } - @Override public int read(byte[] buffer, int offset, int len) { - inLine = true; - try { - int re = super.read(buffer, offset, len); - return re; - } catch(Exception e) { - throw new RuntimeException("HumanInputStream error"); - } finally { - inLine = false; - } - } - @Override public int available() { - if(pos < length) return 1; - return 0; - } - - // test part - static void assertTrue(boolean bool) { - if(!bool) - throw new RuntimeException(); - } - - public static void test() throws Exception { - - class Tester { - HumanInputStream is; - BufferedReader reader; - Tester(String s) { - is = new HumanInputStream(s); - reader = new BufferedReader(new InputStreamReader(is)); - } - - // three kinds of test method - // 1. read byte by byte from InputStream - void testStreamReadOnce(int expection) throws Exception { - assertTrue(is.read() == expection); - } - void testStreamReadMany(String expection) throws Exception { - char[] keys = expection.toCharArray(); - for(int i=0; i Date: Fri, 28 Jun 2024 13:28:53 +0000 Subject: [PATCH 28/85] 8335237: ubsan: vtableStubs.hpp is_vtable_stub exclude from ubsan checks Reviewed-by: mdoerr, clanger --- src/hotspot/share/code/vtableStubs.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 3993e1e72d5..426753ef008 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" #include "memory/allStatic.hpp" +#include "sanitizers/ub.hpp" #include "utilities/checkedCast.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables @@ -173,6 +174,9 @@ class VtableStub { public: // Query bool is_itable_stub() { return !_is_vtable_stub; } + // We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality + // check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed. + ATTRIBUTE_NO_UBSAN bool is_vtable_stub() { return _is_vtable_stub; } bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } From 45c4eaa5600016d3da5ca769b2519df53835e4f7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 28 Jun 2024 16:26:34 +0000 Subject: [PATCH 29/85] 8335274: SwitchBootstraps.ResolvedEnumLabels.resolvedEnum should be final Reviewed-by: liach, jlahoda --- .../share/classes/java/lang/runtime/SwitchBootstraps.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 3eecd2ab42f..24ee48c1f47 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -358,7 +358,7 @@ private static final class ResolvedEnumLabels implements BiPredicate[] enumDescs; @Stable - private Object[] resolvedEnum; + private final Object[] resolvedEnum; public ResolvedEnumLabels(MethodHandles.Lookup lookup, EnumDesc[] enumDescs) { this.lookup = lookup; From 79a3554e1da604627b3a010dc269c1bd914c79d3 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 28 Jun 2024 19:01:36 +0000 Subject: [PATCH 30/85] 8335124: com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java failed with CPU time out of expected range Reviewed-by: phh, cjplummer --- .../com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java index 83e37f0b475..6b0302aafbf 100644 --- a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java +++ b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java @@ -75,7 +75,6 @@ public static void main(String[] argv) // threads block after doing some computation waitUntilThreadBlocked(); - long times[] = mbean.getThreadCpuTime(ids); long userTimes[] = mbean.getThreadUserTime(ids); @@ -222,6 +221,8 @@ private static void waitUntilThreadBlocked() } } } + // Account for threads using CPU for a few millis after their WAITING state is visible: + goSleep(500); } public static void doit() { From 3e23e9c535e0ed1d7517a836d4703c7fb3e917e4 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 28 Jun 2024 19:17:24 +0000 Subject: [PATCH 31/85] 8335344: test/jdk/sun/security/tools/keytool/NssTest.java fails to compile Reviewed-by: weijun --- test/jdk/sun/security/tools/keytool/NssTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/tools/keytool/NssTest.java b/test/jdk/sun/security/tools/keytool/NssTest.java index db5d1240153..1ed2d4c3f39 100644 --- a/test/jdk/sun/security/tools/keytool/NssTest.java +++ b/test/jdk/sun/security/tools/keytool/NssTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ /* * @test * @summary It tests (almost) all keytool behaviors with NSS. - * @library /test/lib /test/jdk/sun/security/pkcs11 + * @library /test/lib /test/jdk/sun/security/pkcs11 /java/security/testlibrary * @modules java.base/sun.security.tools.keytool * java.base/sun.security.util * java.base/sun.security.x509 From 166f9d9ac099fa971805511b32e1cae5c6c108e0 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 28 Jun 2024 19:36:00 +0000 Subject: [PATCH 32/85] 8335221: Some C2 intrinsics incorrectly assume that type argument is compile-time constant Reviewed-by: roland, chagedorn --- src/hotspot/share/opto/library_call.cpp | 104 +++++++++++++++--------- src/hotspot/share/opto/library_call.hpp | 1 + 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 0148d985bc5..ebe9258f99b 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5489,42 +5489,72 @@ void LibraryCallKit::create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_ uncommon_trap_call->set_req(0, top()); // not used anymore, kill it } +// Common checks for array sorting intrinsics arguments. +// Returns `true` if checks passed. +bool LibraryCallKit::check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt) { + // check address of the class + if (elementType == nullptr || elementType->is_top()) { + return false; // dead path + } + const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); + if (elem_klass == nullptr) { + return false; // dead path + } + // java_mirror_type() returns non-null for compile-time Class constants only + ciType* elem_type = elem_klass->java_mirror_type(); + if (elem_type == nullptr) { + return false; + } + bt = elem_type->basic_type(); + // Disable the intrinsic if the CPU does not support SIMD sort + if (!Matcher::supports_simd_sort(bt)) { + return false; + } + // check address of the array + if (obj == nullptr || obj->is_top()) { + return false; // dead path + } + const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); + if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM) { + return false; // failed input validation + } + return true; +} + //------------------------------inline_array_partition----------------------- bool LibraryCallKit::inline_array_partition() { + address stubAddr = StubRoutines::select_array_partition_function(); + if (stubAddr == nullptr) { + return false; // Intrinsic's stub is not implemented on this platform + } + assert(callee()->signature()->size() == 9, "arrayPartition has 8 parameters (one long)"); - Node* elementType = null_check(argument(0)); + // no receiver because it is a static method + Node* elementType = argument(0); Node* obj = argument(1); - Node* offset = argument(2); + Node* offset = argument(2); // long Node* fromIndex = argument(4); Node* toIndex = argument(5); Node* indexPivot1 = argument(6); Node* indexPivot2 = argument(7); + // PartitionOperation: argument(8) is ignored Node* pivotIndices = nullptr; + BasicType bt = T_ILLEGAL; + if (!check_array_sort_arguments(elementType, obj, bt)) { + return false; + } + null_check(obj); + // If obj is dead, only null-path is taken. + if (stopped()) { + return true; + } // Set the original stack and the reexecute bit for the interpreter to reexecute // the bytecode that invokes DualPivotQuicksort.partition() if deoptimization happens. { PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); - ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); - BasicType bt = elem_type->basic_type(); - // Disable the intrinsic if the CPU does not support SIMD sort - if (!Matcher::supports_simd_sort(bt)) { - return false; - } - address stubAddr = nullptr; - stubAddr = StubRoutines::select_array_partition_function(); - // stub not loaded - if (stubAddr == nullptr) { - return false; - } - // get the address of the array - const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); - if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { - return false; // failed input validation - } Node* obj_adr = make_unsafe_address(obj, offset); // create the pivotIndices array of type int and size = 2 @@ -5557,31 +5587,29 @@ bool LibraryCallKit::inline_array_partition() { //------------------------------inline_array_sort----------------------- bool LibraryCallKit::inline_array_sort() { + address stubAddr = StubRoutines::select_arraysort_function(); + if (stubAddr == nullptr) { + return false; // Intrinsic's stub is not implemented on this platform + } + assert(callee()->signature()->size() == 7, "arraySort has 6 parameters (one long)"); - Node* elementType = null_check(argument(0)); + // no receiver because it is a static method + Node* elementType = argument(0); Node* obj = argument(1); - Node* offset = argument(2); + Node* offset = argument(2); // long Node* fromIndex = argument(4); Node* toIndex = argument(5); + // SortOperation: argument(6) is ignored - const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); - ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); - BasicType bt = elem_type->basic_type(); - // Disable the intrinsic if the CPU does not support SIMD sort - if (!Matcher::supports_simd_sort(bt)) { - return false; - } - address stubAddr = nullptr; - stubAddr = StubRoutines::select_arraysort_function(); - //stub not loaded - if (stubAddr == nullptr) { + BasicType bt = T_ILLEGAL; + + if (!check_array_sort_arguments(elementType, obj, bt)) { return false; } - - // get address of the array - const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); - if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { - return false; // failed input validation + null_check(obj); + // If obj is dead, only null-path is taken. + if (stopped()) { + return true; } Node* obj_adr = make_unsafe_address(obj, offset); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 941282ce2e7..313e8c39544 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -279,6 +279,7 @@ class LibraryCallKit : public GraphKit { JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms_before_guards, int saved_reexecute_sp, uint new_idx); + bool check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt); bool inline_array_sort(); bool inline_array_partition(); typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; From 5d866bf17d96bd0f0e4545d7eee5912eda2e3a94 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 28 Jun 2024 22:27:34 +0000 Subject: [PATCH 33/85] 8335252: Reduce size of j.u.Formatter.Conversion#isValid Reviewed-by: redestad --- src/java.base/share/classes/java/util/Formatter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index a7d95ee5780..41b9540001c 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -4967,9 +4967,9 @@ static boolean isValid(char c) { DECIMAL_FLOAT, HEXADECIMAL_FLOAT, HEXADECIMAL_FLOAT_UPPER, - LINE_SEPARATOR, - PERCENT_SIGN -> true; - default -> false; + LINE_SEPARATOR -> true; + // Don't put PERCENT_SIGN inside switch, as that will make the method size exceed 325 and cannot be inlined. + default -> c == PERCENT_SIGN; }; } From 8350b1daedae8ef5785a7165e664b1d3149b18b7 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sat, 29 Jun 2024 05:04:47 +0000 Subject: [PATCH 34/85] 8335294: Fix simple -Wzero-as-null-pointer-constant warnings in gc code Reviewed-by: tschatzl, coleenp, jwaters --- .../gc/x/xPhysicalMemoryBacking_linux.cpp | 6 +++--- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 6 +++--- .../share/gc/parallel/parMarkBitMap.cpp | 4 ++-- .../share/gc/parallel/parallelScavengeHeap.cpp | 2 +- .../share/gc/parallel/psParallelCompact.cpp | 6 +++--- src/hotspot/share/gc/z/zPage.inline.hpp | 3 +-- .../gc/gctests/nativeGC01/libnativeGC01.cpp | 6 +++--- .../gc/gctests/nativeGC02/libnativeGC02.cpp | 8 ++++---- .../gc/gctests/nativeGC03/libnativeGC03.cpp | 2 +- .../gc/gctests/nativeGC05/libnativeGC05.cpp | 18 +++++++++--------- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp index 5db59741a58..35625f613d3 100644 --- a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -389,7 +389,7 @@ XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(size_t offset, si // On hugetlbfs, mapping a file segment will fail immediately, without // the need to touch the mapped pages first, if there aren't enough huge // pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); if (addr == MAP_FAILED) { // Failed return errno; @@ -439,7 +439,7 @@ static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(size_t offset, size_t length) const { // On tmpfs, we need to touch the mapped pages to figure out // if there are enough pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); if (addr == MAP_FAILED) { // Failed return errno; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 76f9d90cd71..b80124cc34e 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,7 +391,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(zoffset offset, s // On hugetlbfs, mapping a file segment will fail immediately, without // the need to touch the mapped pages first, if there aren't enough huge // pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); if (addr == MAP_FAILED) { // Failed return errno; @@ -441,7 +441,7 @@ static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zoffset offset, size_t length) const { // On tmpfs, we need to touch the mapped pages to figure out // if there are enough pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); if (addr == MAP_FAILED) { // Failed return errno; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index 434b719aa13..658c3ef106f 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) return true; } - _heap_start = 0; + _heap_start = nullptr; _heap_size = 0; if (_virtual_space != nullptr) { delete _virtual_space; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 2984cedafe1..665b14bb1ea 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -661,7 +661,7 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { "addr should be in allocated part of old gen"); return old_gen()->start_array()->object_start((HeapWord*)addr); } - return 0; + return nullptr; } bool ParallelScavengeHeap::block_is_obj(const HeapWord* addr) const { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 6c085034384..b4fe706d1e4 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -237,7 +237,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); PSVirtualSpace* vspace = new PSVirtualSpace(rs, page_sz); - if (vspace != 0) { + if (vspace != nullptr) { if (vspace->expand_by(_reserved_byte_size)) { return vspace; } @@ -246,7 +246,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) rs.release(); } - return 0; + return nullptr; } bool ParallelCompactData::initialize_region_data(size_t heap_size) @@ -255,7 +255,7 @@ bool ParallelCompactData::initialize_region_data(size_t heap_size) const size_t count = heap_size >> Log2RegionSize; _region_vspace = create_vspace(count, sizeof(RegionData)); - if (_region_vspace != 0) { + if (_region_vspace != nullptr) { _region_data = (RegionData*)_region_vspace->reserved_low_addr(); _region_count = count; return true; diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index ff5fe0bbd6c..0b4ee28ba7d 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ inline const char* ZPage::type_to_string() const { default: fatal("Unexpected page type"); - return 0; } } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp index 63aed51a897..efd1fd3fa3a 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ Java_gc_gctests_nativeGC01_nativeGC01_nativeMethod01 */ cls = env->GetObjectClass(obj); mid = env->GetMethodID(cls, "callbackGC", "()V"); - if (mid == 0) { + if (mid == nullptr) { printf("couldnt locate method callbackGC()"); return -1; } @@ -56,7 +56,7 @@ Java_gc_gctests_nativeGC01_nativeGC01_nativeMethod01 clss = env->GetObjectClass(linked_list); mid2 = env->GetMethodID(clss, "getLength", "()I"); - if (mid2 == 0) { + if (mid2 == nullptr) { printf("couldnt locate method getLength()"); return -1; } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp index e6db8cf6184..eec3fa3e8e8 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 clss = env->GetObjectClass(obj); fid = env->GetFieldID(clss, "cl", "Lnsk/share/gc/CircularLinkedList;"); - if (fid == 0) { + if (fid == nullptr) { printf("could not locate field - cl\n"); return -1; } @@ -53,7 +53,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 cls = env->GetObjectClass(obj); mid = env->GetMethodID(cls, "callbackGC", "()V"); - if (mid == 0) { + if (mid == nullptr) { printf("couldnt locate method callbackGC()\n"); return -1; } @@ -66,7 +66,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 clss = env->GetObjectClass(linked_list); mid2 = env->GetMethodID(clss, "getLength", "(Lnsk/share/gc/CircularLinkedList;)I"); - if (mid2 == 0) { + if (mid2 == nullptr) { printf("couldnt locate method getLength(CircularLinkedList)\n"); return -1; } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp index 2c97863db5a..e3f54ec86ec 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp @@ -46,7 +46,7 @@ Java_gc_gctests_nativeGC03_nativeGC03_nativeMethod03 clss = env->GetObjectClass(obj); mid = env->GetMethodID(clss, "fillArray", "()V"); - if (mid == 0) { + if (mid == nullptr) { return; } env->CallVoidMethod(obj, mid); diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp index 4bfaeda1f06..a796cf938bb 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,8 @@ extern "C" { JNIEXPORT void JNICALL Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers (JNIEnv *env, jobject obj, jobject matrix, jobject stack) { - jclass matrixClass, stackClass, pairClass = 0; - jmethodID stack_pop_mid, stack_empty_mid, matrix_repopulate_mid, pair_geti_mid = 0, pair_getj_mid = 0; + jclass matrixClass, stackClass, pairClass = nullptr; + jmethodID stack_pop_mid, stack_empty_mid, matrix_repopulate_mid, pair_geti_mid = nullptr, pair_getj_mid = nullptr; jobject pair; jint i, j; jboolean b; @@ -40,18 +40,18 @@ Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers /* GetMethodID's for the pop() and Repopulate() methods */ stack_pop_mid = env->GetMethodID(stackClass, "pop", "()Ljava/lang/Object;"); - if (stack_pop_mid == 0) { + if (stack_pop_mid == nullptr) { printf("could not get a methodID for Stack::pop()\n"); return; } stack_empty_mid = env->GetMethodID(stackClass, "empty", "()Z"); - if (stack_empty_mid == 0) { + if (stack_empty_mid == nullptr) { printf("could not get a methodID for Stack::empty()\n"); return; } matrix_repopulate_mid = env->GetMethodID(matrixClass, "repopulate", "(II)V"); - if (matrix_repopulate_mid == 0) { + if (matrix_repopulate_mid == nullptr) { printf("could not get a methodID for Matrix::repopulate(int, int)\n"); return; } @@ -62,15 +62,15 @@ Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers /** pair = stack.pop() */ pair = env->CallObjectMethod(stack, stack_pop_mid); - if (pairClass == 0) { + if (pairClass == nullptr) { pairClass = env->GetObjectClass(pair); pair_geti_mid = env->GetMethodID(pairClass, "getI", "()I"); - if (pair_geti_mid == 0) { + if (pair_geti_mid == nullptr) { printf("could not get a methodID for IndexPair::getI()\n"); return; } pair_getj_mid = env->GetMethodID(pairClass, "getJ", "()I"); - if (pair_getj_mid == 0) { + if (pair_getj_mid == nullptr) { printf("could not get a methodID for IndexPair::getJ()\n"); return; } From bb18498d71dddf49db9bdfac886aed9ae123651d Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Sat, 29 Jun 2024 08:19:33 +0000 Subject: [PATCH 35/85] 8335349: jcmd VM.classloaders "fold" option should be optional Reviewed-by: cjplummer, stuefe --- src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp index f89090fbb5c..8a8113db403 100644 --- a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp +++ b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,7 +39,7 @@ ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool he : DCmdWithParser(output, heap), _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false"), _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false"), - _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", true, "true") { + _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", false, "true") { _dcmdparser.add_dcmd_option(&_show_classes); _dcmdparser.add_dcmd_option(&_verbose); _dcmdparser.add_dcmd_option(&_fold); From d9bcf061450ebfb7fe02b5a50c855db1d9178e5d Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Sat, 29 Jun 2024 20:40:51 +0000 Subject: [PATCH 36/85] 8335217: Fix memory ordering in ClassLoaderData::ChunkedHandleList Reviewed-by: dholmes, stefank, eosterlund --- src/hotspot/share/classfile/classLoaderData.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 16837da9cf2..de4490e73f3 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -202,9 +202,9 @@ OopHandle ClassLoaderData::ChunkedHandleList::add(oop o) { int ClassLoaderData::ChunkedHandleList::count() const { int count = 0; - Chunk* chunk = _head; + Chunk* chunk = Atomic::load_acquire(&_head); while (chunk != nullptr) { - count += chunk->_size; + count += Atomic::load(&chunk->_size); chunk = chunk->_next; } return count; @@ -258,9 +258,9 @@ bool ClassLoaderData::ChunkedHandleList::contains(oop p) { #ifndef PRODUCT bool ClassLoaderData::ChunkedHandleList::owner_of(oop* oop_handle) { - Chunk* chunk = _head; + Chunk* chunk = Atomic::load_acquire(&_head); while (chunk != nullptr) { - if (&(chunk->_data[0]) <= oop_handle && oop_handle < &(chunk->_data[chunk->_size])) { + if (&(chunk->_data[0]) <= oop_handle && oop_handle < &(chunk->_data[Atomic::load(&chunk->_size)])) { return true; } chunk = chunk->_next; From 53242cdf9ef17c502ebd541e84370e7c158639c1 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Jul 2024 06:37:09 +0000 Subject: [PATCH 37/85] 8335283: Build failure due to 'no_sanitize' attribute directive ignored Reviewed-by: shade, tschatzl, kbarrett, jwaters --- src/hotspot/share/sanitizers/ub.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/sanitizers/ub.hpp b/src/hotspot/share/sanitizers/ub.hpp index 23e8ef4576c..66cd014c35c 100644 --- a/src/hotspot/share/sanitizers/ub.hpp +++ b/src/hotspot/share/sanitizers/ub.hpp @@ -32,9 +32,11 @@ // following function or method. // Useful if the function or method is known to do something special or even 'dangerous', for // example causing desired signals/crashes. +#ifdef UNDEFINED_BEHAVIOR_SANITIZER #if defined(__clang__) || defined(__GNUC__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) #endif +#endif #ifndef ATTRIBUTE_NO_UBSAN #define ATTRIBUTE_NO_UBSAN From c7e9ebb4cfff56b7a977eb2942f563f96b3336bd Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Mon, 1 Jul 2024 08:07:42 +0000 Subject: [PATCH 38/85] 8331732: [PPC64] Unify and optimize code which converts != 0 to 1 Reviewed-by: mdoerr, amitkumar --- src/hotspot/cpu/ppc/assembler_ppc.hpp | 7 +++-- src/hotspot/cpu/ppc/assembler_ppc.inline.hpp | 9 +++++-- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 9 ++----- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 2 ++ .../cpu/ppc/macroAssembler_ppc.inline.hpp | 27 +++++++++++++++++-- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 6 +---- .../ppc/templateInterpreterGenerator_ppc.cpp | 4 +-- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index 61a5d6425ee..d18574f50a9 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -350,6 +350,7 @@ class Assembler : public AbstractAssembler { SETBC_OPCODE = (31u << OPCODE_SHIFT | 384u << 1), SETNBC_OPCODE = (31u << OPCODE_SHIFT | 448u << 1), + SETBCR_OPCODE = (31u << OPCODE_SHIFT | 416u << 1), // condition register logic instructions CRAND_OPCODE = (19u << OPCODE_SHIFT | 257u << 1), @@ -1780,6 +1781,8 @@ class Assembler : public AbstractAssembler { inline void setbc( Register d, ConditionRegister cr, Condition cc); inline void setnbc(Register d, int biint); inline void setnbc(Register d, ConditionRegister cr, Condition cc); + inline void setbcr(Register d, int biint); + inline void setbcr(Register d, ConditionRegister cr, Condition cc); // Special purpose registers // Exception Register diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index d78dec964cb..98c8b629844 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2020 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -419,6 +419,11 @@ inline void Assembler::setnbc(Register d, int biint) inline void Assembler::setnbc(Register d, ConditionRegister cr, Condition cc) { setnbc(d, bi0(cr, cc)); } +inline void Assembler::setbcr(Register d, int biint) + { emit_int32(SETBCR_OPCODE | rt(d) | bi(biint)); } +inline void Assembler::setbcr(Register d, ConditionRegister cr, Condition cc) { + setbcr(d, bi0(cr, cc)); +} // Special purpose registers // Exception Register diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 0527cb306b2..f9e584a1e6b 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2383,10 +2383,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, addi(r_array_base, r_array_base, Array::base_offset_in_bytes()); // convert !=0 to 1 - neg(R0, result); - orr(result, result, R0); - srdi(result, result, 63); - + normalize_bool(result, R0, true); const Register linear_result = r_array_index; // reuse li(linear_result, 1); cmpdi(CCR0, r_array_length, 0); @@ -2395,9 +2392,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, bind(failure); // convert !=0 to 1 - neg(R0, linear_result); - orr(linear_result, linear_result, R0); - srdi(linear_result, linear_result, 63); + normalize_bool(linear_result, R0, true); cmpd(CCR0, result, linear_result); beq(CCR0, passed); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 4f2ff708a46..15b5e26f8f6 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -178,6 +178,8 @@ class MacroAssembler: public Assembler { void inline set_cmp3(Register dst); // set dst to (treat_unordered_like_less ? -1 : +1) void inline set_cmpu3(Register dst, bool treat_unordered_like_less); + // Branch-free implementation to convert !=0 to 1. + void inline normalize_bool(Register dst, Register temp = R0, bool is_64bit = false); inline void pd_patch_instruction(address branch, address target, const char* file, int line); NOT_PRODUCT(static void pd_print_patched_instruction(address branch);) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp index f81d49684c9..e9c6fd38f45 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,6 +264,29 @@ inline void MacroAssembler::set_cmpu3(Register dst, bool treat_unordered_like_le set_cmp3(dst); } +// Branch-free implementation to convert !=0 to 1 +// Set register dst to 1 if dst is non-zero. Uses setbcr instruction on Power10. +inline void MacroAssembler::normalize_bool(Register dst, Register temp, bool is_64bit) { + + if (VM_Version::has_brw()) { + if (is_64bit) { + cmpdi(CCR0, dst, 0); + } else { + cmpwi(CCR0, dst, 0); + } + setbcr(dst, CCR0, Assembler::equal); + } else { + assert_different_registers(temp, dst); + neg(temp, dst); + orr(temp, dst, temp); + if (is_64bit) { + srdi(dst, temp, 63); + } else { + srwi(dst, temp, 31); + } + } +} + // Convenience bc_far versions inline void MacroAssembler::blt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, less), L, optimize); } inline void MacroAssembler::bgt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, greater), L, optimize); } diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 14aa768e3ff..9b5a86bc45b 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2472,11 +2472,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, case T_ARRAY: break; case T_BOOLEAN: { // 0 -> false(0); !0 -> true(1) - Label skip_modify; - __ cmpwi(CCR0, R3_RET, 0); - __ beq(CCR0, skip_modify); - __ li(R3_RET, 1); - __ bind(skip_modify); + __ normalize_bool(R3_RET); break; } case T_BYTE: { // sign extension diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index c4eaf0493e3..4caae200253 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -372,9 +372,7 @@ address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type switch (type) { case T_BOOLEAN: // convert !=0 to 1 - __ neg(R0, R3_RET); - __ orr(R0, R3_RET, R0); - __ srwi(R3_RET, R0, 31); + __ normalize_bool(R3_RET); break; case T_BYTE: // sign extend 8 bits From 71e3798bf67cddef37a8b4e377c4bf21dbd01567 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 1 Jul 2024 08:12:20 +0000 Subject: [PATCH 39/85] 8335308: compiler/uncommontrap/DeoptReallocFailure.java times out with SerialGC on Windows Reviewed-by: kvn, thartmann, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 -- .../jtreg/compiler/uncommontrap/DeoptReallocFailure.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index febde61c4fd..254e621bfdd 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -70,8 +70,6 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all -compiler/uncommontrap/DeoptReallocFailure.java 8335308 windows-x64 - ############################################################################# # :hotspot_gc diff --git a/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java b/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java index 949a3ecb5c2..96c79864b52 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java @@ -63,7 +63,7 @@ public static synchronized long test() { NoEscape[] noEscape = new NoEscape[45]; noEscape[0] = new NoEscape(); for (int i=0;i<1024*256;i++) { - root.array[i]= new Object[45]; + root.array[i]= new Object[4500]; } return noEscape[0].f1; } From 0a6ffa57954ddf4f92205205a5a1bada813d127a Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Mon, 1 Jul 2024 08:47:29 +0000 Subject: [PATCH 40/85] 8261242: [Linux] OSContainer::is_containerized() returns true when run outside a container Reviewed-by: stuefe, iklam --- .../os/linux/cgroupSubsystem_linux.cpp | 119 +++++++++++++++--- .../os/linux/cgroupSubsystem_linux.hpp | 7 +- .../os/linux/cgroupV1Subsystem_linux.cpp | 11 ++ .../os/linux/cgroupV1Subsystem_linux.hpp | 8 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 4 + .../os/linux/cgroupV2Subsystem_linux.hpp | 6 +- src/hotspot/os/linux/osContainer_linux.cpp | 39 +++++- src/hotspot/share/include/jvm.h | 3 + src/hotspot/share/prims/jvm.cpp | 12 ++ .../jdk/internal/platform/CgroupMetrics.java | 6 + .../internal/platform/CgroupSubsystem.java | 5 + .../linux/native/libjava/CgroupMetrics.c | 6 + .../jdk/internal/platform/Metrics.java | 17 +++ .../classes/sun/launcher/LauncherHelper.java | 4 + .../runtime/test_cgroupSubsystem_linux.cpp | 9 +- test/hotspot/jtreg/ProblemList.txt | 1 - ...{PlainRead.java => TestContainerized.java} | 42 +------ .../platform/cgroup/TestSystemSettings.java | 45 +++++++ .../lib/containers/cgroup/MetricsTester.java | 10 ++ 19 files changed, 290 insertions(+), 64 deletions(-) rename test/hotspot/jtreg/containers/cgroup/{PlainRead.java => TestContainerized.java} (54%) create mode 100644 test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 560589c3602..0dbd6ffd52b 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -63,7 +63,9 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { // Construct the subsystem, free resources and return // Note: any index in cg_infos will do as the path is the same for // all controllers. - CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, cg_infos[MEMORY_IDX]._cgroup_path); + CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, + cg_infos[MEMORY_IDX]._cgroup_path, + cg_infos[MEMORY_IDX]._read_only); log_debug(os, container)("Detected cgroups v2 unified hierarchy"); cleanup(cg_infos); return new CgroupV2Subsystem(unified); @@ -100,19 +102,19 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupInfo info = cg_infos[i]; if (info._data_complete) { // pids controller might have incomplete data if (strcmp(info._name, "memory") == 0) { - memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path); + memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path, info._read_only); memory->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuset") == 0) { - cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuset->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpu") == 0) { - cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpu->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuacct") == 0) { - cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuacct->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "pids") == 0) { - pids = new CgroupV1Controller(info._root_mount_path, info._mount_path); + pids = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); pids->set_subsystem_path(info._cgroup_path); } } else { @@ -127,7 +129,8 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, int controller, const char* name, char* mount_path, - char* root_path) { + char* root_path, + bool read_only) { if (cg_infos[controller]._mount_path != nullptr) { // On some systems duplicate controllers get mounted in addition to // the main cgroup controllers most likely under /sys/fs/cgroup. In that @@ -139,6 +142,7 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, os::free(cg_infos[controller]._root_mount_path); cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } else { log_debug(os, container)("Duplicate %s controllers detected. Picking %s, skipping %s.", name, cg_infos[controller]._mount_path, mount_path); @@ -146,9 +150,66 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, } else { cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } } +/* + * Determine whether or not the mount options, which are comma separated, + * contain the 'ro' string. + */ +static bool find_ro_opt(char* mount_opts) { + char* token; + char* mo_ptr = mount_opts; + // mount options are comma-separated (man proc). + while ((token = strsep(&mo_ptr, ",")) != NULL) { + if (strcmp(token, "ro") == 0) { + return true; + } + } + return false; +} + +/* + * Read values of a /proc/self/mountinfo line into variables. For cgroups v1 + * super options are needed. On cgroups v2 super options are not used. + * + * The scanning of a single mountinfo line entry is as follows: + * + * 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + * (1) (2) (3):(4) (5) (6) (7) (8) (9) (10) (11) (12) + * + * The numbers in parentheses are labels for the descriptions below: + * + * (1) mount ID: matched with '%*d' and discarded + * (2) parent ID: matched with '%*d' and discarded + * (3) major: ---,---> major, minor separated by ':'. matched with '%*d:%*d' and discarded + * (4) minor: ---' + * (5) root: matched with '%s' and captured in 'tmproot'. Must be non-empty. + * (6) mount point: matched with '%s' and captured in 'tmpmount'. Must be non-empty. + * (7) mount options: matched with '%s' and captured in 'mount_opts'. Must be non-empty. + * (8) optional fields: ---,---> matched with '%*[^-]-'. Anything not a hyphen, followed by a hyphen + * (9) separator: ---' and discarded. Note: The discarded match is space characters if there + * are no optionals. Otherwise it includes the optional fields as well. + * (10) filesystem type: matched with '%s' and captured in 'tmp_fs_type' + * (11) mount source: matched with '%*s' and discarded + * (12) super options: matched with '%s' and captured in 'tmpcgroups' + */ +static inline bool match_mount_info_line(char* line, + char* tmproot, + char* tmpmount, + char* mount_opts, + char* tmp_fs_type, + char* tmpcgroups) { + return sscanf(line, + "%*d %*d %*d:%*d %s %s %s%*[^-]- %s %*s %s", + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups) == 5; +} + bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, const char* proc_cgroups, const char* proc_self_cgroup, @@ -318,26 +379,40 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, char tmproot[MAXPATHLEN+1]; char tmpmount[MAXPATHLEN+1]; char tmpcgroups[MAXPATHLEN+1]; + char mount_opts[MAXPATHLEN+1]; char *cptr = tmpcgroups; char *token; - // Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so - // as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 - // block in the hybrid case. - if (is_cgroupsV2 && sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %*s", tmproot, tmpmount, tmp_fs_type) == 3) { + /* Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so + * as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 + * block in the hybrid case. + * + * We collect the read only mount option in the cgroup infos so as to have that + * info ready when determining is_containerized(). + */ + if (is_cgroupsV2 && match_mount_info_line(p, + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups /* unused */)) { // we likely have an early match return (e.g. cgroup fs match), be sure we have cgroup2 as fstype if (strcmp("cgroup2", tmp_fs_type) == 0) { cgroupv2_mount_point_found = true; any_cgroup_mounts_found = true; + // For unified we only have a single line with cgroup2 fs type. + // Therefore use that option for all CG info structs. + bool ro_option = find_ro_opt(mount_opts); for (int i = 0; i < CG_INFO_LENGTH; i++) { - set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot); + set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot, ro_option); } } } /* Cgroup v1 relevant info * - * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids + * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids. For each controller + * determine whether or not they show up as mounted read only or not. * * Example for docker: * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory @@ -346,8 +421,9 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory * * 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids + * */ - if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s", tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4) { + if (match_mount_info_line(p, tmproot, tmpmount, mount_opts, tmp_fs_type, tmpcgroups)) { if (strcmp("cgroup", tmp_fs_type) != 0) { // Skip cgroup2 fs lines on hybrid or unified hierarchy. continue; @@ -355,23 +431,28 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, while ((token = strsep(&cptr, ",")) != nullptr) { if (strcmp(token, "memory") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot, ro_option); cg_infos[MEMORY_IDX]._data_complete = true; } else if (strcmp(token, "cpuset") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUSET_IDX]._data_complete = true; } else if (strcmp(token, "cpu") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPU_IDX]._data_complete = true; } else if (strcmp(token, "cpuacct") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUACCT_IDX]._data_complete = true; } else if (strcmp(token, "pids") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot, ro_option); cg_infos[PIDS_IDX]._data_complete = true; } } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 6c17ff4508d..00419c77570 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -105,6 +105,7 @@ class CgroupController: public CHeapObj { public: virtual char* subsystem_path() = 0; + virtual bool is_read_only() = 0; /* Read a numerical value as unsigned long * @@ -211,6 +212,7 @@ class CgroupSubsystem: public CHeapObj { virtual jlong memory_max_usage_in_bytes() = 0; virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; + virtual bool is_containerized() = 0; virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; @@ -233,6 +235,7 @@ class CgroupInfo : public StackObj { char* _name; int _hierarchy_id; bool _enabled; + bool _read_only; // whether or not the mount path is mounted read-only bool _data_complete; // indicating cgroup v1 data is complete for this controller char* _cgroup_path; // cgroup controller path from /proc/self/cgroup char* _root_mount_path; // root mount path from /proc/self/mountinfo. Unused for cgroup v2 @@ -243,6 +246,7 @@ class CgroupInfo : public StackObj { _name = nullptr; _hierarchy_id = -1; _enabled = false; + _read_only = false; _data_complete = false; _cgroup_path = nullptr; _root_mount_path = nullptr; @@ -274,7 +278,8 @@ class CgroupSubsystemFactory: AllStatic { int controller, const char* name, char* mount_path, - char* root_path); + char* root_path, + bool read_only); // Determine the cgroup type (version 1 or version 2), given // relevant paths to files. Sets 'flags' accordingly. static bool determine_type(CgroupInfo* cg_infos, diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 72adaa23b81..3f6ae813810 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -215,6 +215,17 @@ jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { } } +bool CgroupV1Subsystem::is_containerized() { + // containerized iff all required controllers are mounted + // read-only. See OSContainer::is_containerized() for + // the full logic. + // + return _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only() && + _cpuacct->is_read_only() && + _cpuset->is_read_only(); +} + /* memory_usage_in_bytes * * Return the amount of used memory for this process. diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 254b17de0ba..2b67678c2e8 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -36,19 +36,22 @@ class CgroupV1Controller: public CgroupController { /* mountinfo contents */ char *_root; char *_mount_point; + bool _read_only; /* Constructed subsystem directory */ char *_path; public: - CgroupV1Controller(char *root, char *mountpoint) { + CgroupV1Controller(char *root, char *mountpoint, bool ro) { _root = os::strdup(root); _mount_point = os::strdup(mountpoint); _path = nullptr; + _read_only = ro; } virtual void set_subsystem_path(char *cgroup_path); char *subsystem_path() { return _path; } + bool is_read_only() { return _read_only; } }; class CgroupV1MemoryController: public CgroupV1Controller { @@ -65,7 +68,7 @@ class CgroupV1MemoryController: public CgroupV1Controller { void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } public: - CgroupV1MemoryController(char *root, char *mountpoint) : CgroupV1Controller(root, mountpoint) { + CgroupV1MemoryController(char *root, char *mountpoint, bool ro) : CgroupV1Controller(root, mountpoint, ro) { _uses_mem_hierarchy = false; } @@ -97,6 +100,7 @@ class CgroupV1Subsystem: public CgroupSubsystem { jlong pids_max(); jlong pids_current(); + bool is_containerized(); void print_version_specific_info(outputStream* st); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 1ba7c1e69d5..1f97b021239 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -94,6 +94,10 @@ int CgroupV2Subsystem::cpu_quota() { return limit; } +bool CgroupV2Subsystem::is_containerized() { + return _unified->is_read_only(); +} + char* CgroupV2Subsystem::cpu_cpuset_cpus() { char cpus[1024]; CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index a004c8f75b9..8e06466a138 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -33,19 +33,22 @@ class CgroupV2Controller: public CgroupController { char *_mount_path; /* The cgroup path for the controller */ char *_cgroup_path; + bool _read_only; /* Constructed full path to the subsystem directory */ char *_path; static char* construct_path(char* mount_path, char *cgroup_path); public: - CgroupV2Controller(char * mount_path, char *cgroup_path) { + CgroupV2Controller(char * mount_path, char *cgroup_path, bool ro) { _mount_path = mount_path; _cgroup_path = os::strdup(cgroup_path); _path = construct_path(mount_path, cgroup_path); + _read_only = ro; } char *subsystem_path() { return _path; } + bool is_read_only() { return _read_only; } }; class CgroupV2Subsystem: public CgroupSubsystem { @@ -83,6 +86,7 @@ class CgroupV2Subsystem: public CgroupSubsystem { jlong pids_max(); jlong pids_current(); + bool is_containerized(); void print_version_specific_info(outputStream* st); const char * container_type() { diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index fdb138c864f..25e8eb46410 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -58,8 +58,43 @@ void OSContainer::init() { if (cgroup_subsystem == nullptr) { return; // Required subsystem files not found or other error } - - _is_containerized = true; + /* + * In order to avoid a false positive on is_containerized() on + * Linux systems outside a container *and* to ensure compatibility + * with in-container usage, we detemine is_containerized() by two + * steps: + * 1.) Determine if all the cgroup controllers are mounted read only. + * If yes, is_containerized() == true. Otherwise, do the fallback + * in 2.) + * 2.) Query for memory and cpu limits. If any limit is set, we set + * is_containerized() == true. + * + * Step 1.) covers the basic in container use-cases. Step 2.) ensures + * that limits enforced by other means (e.g. systemd slice) are properly + * detected. + */ + const char *reason; + bool any_mem_cpu_limit_present = false; + bool controllers_read_only = cgroup_subsystem->is_containerized(); + if (controllers_read_only) { + // in-container case + reason = " because all controllers are mounted read-only (container case)"; + } else { + // We can be in one of two cases: + // 1.) On a physical Linux system without any limit + // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) + any_mem_cpu_limit_present = cgroup_subsystem->memory_limit_in_bytes() > 0 || + os::Linux::active_processor_count() != cgroup_subsystem->active_processor_count(); + if (any_mem_cpu_limit_present) { + reason = " because either a cpu or a memory limit is present"; + } else { + reason = " because no cpu or memory limit is present"; + } + } + _is_containerized = controllers_read_only || any_mem_cpu_limit_present; + log_debug(os, container)("OSContainer::init: is_containerized() = %s%s", + _is_containerized ? "true" : "false", + reason); } const char * OSContainer::container_type() { diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 99cdac3aec5..0aad9160ae8 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -150,6 +150,9 @@ JVM_ActiveProcessorCount(void); JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void); +JNIEXPORT jboolean JNICALL +JVM_IsContainerized(void); + JNIEXPORT void * JNICALL JVM_LoadZipLibrary(); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 9588f32e6b3..d55c8a6be65 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -113,6 +113,9 @@ #if INCLUDE_MANAGEMENT #include "services/finalizerService.hpp" #endif +#ifdef LINUX +#include "osContainer_linux.hpp" +#endif #include @@ -496,6 +499,15 @@ JVM_LEAF(jboolean, JVM_IsUseContainerSupport(void)) return JNI_FALSE; JVM_END +JVM_LEAF(jboolean, JVM_IsContainerized(void)) +#ifdef LINUX + if (OSContainer::is_containerized()) { + return JNI_TRUE; + } +#endif + return JNI_FALSE; +JVM_END + // java.lang.Throwable ////////////////////////////////////////////////////// JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) diff --git a/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java b/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java index 8797711bf4b..af551a07b1e 100644 --- a/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java +++ b/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java @@ -35,6 +35,11 @@ public class CgroupMetrics implements Metrics { this.subsystem = Objects.requireNonNull(subsystem); } + @Override + public boolean isContainerized() { + return isContainerized0(); + } + @Override public String getProvider() { return subsystem.getProvider(); @@ -194,6 +199,7 @@ public static Metrics getInstance() { } private static native boolean isUseContainerSupport(); + private static native boolean isContainerized0(); private static native long getTotalMemorySize0(); private static native long getTotalSwapSize0(); diff --git a/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java b/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java index 952de13e9f2..7df86d03ff4 100644 --- a/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java +++ b/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java @@ -31,6 +31,11 @@ */ public interface CgroupSubsystem extends Metrics { + + default boolean isContainerized() { + return false; // This default impl is never used + } + /** * Returned for metrics of type long if the underlying implementation * has determined that no limit is being imposed. diff --git a/src/java.base/linux/native/libjava/CgroupMetrics.c b/src/java.base/linux/native/libjava/CgroupMetrics.c index a5e41167bc3..e2f98633459 100644 --- a/src/java.base/linux/native/libjava/CgroupMetrics.c +++ b/src/java.base/linux/native/libjava/CgroupMetrics.c @@ -36,6 +36,12 @@ Java_jdk_internal_platform_CgroupMetrics_isUseContainerSupport(JNIEnv *env, jcla return JVM_IsUseContainerSupport(); } +JNIEXPORT jboolean JNICALL +Java_jdk_internal_platform_CgroupMetrics_isContainerized0(JNIEnv *env, jclass ignored) +{ + return JVM_IsContainerized(); +} + JNIEXPORT jlong JNICALL Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0 (JNIEnv *env, jclass ignored) diff --git a/src/java.base/share/classes/jdk/internal/platform/Metrics.java b/src/java.base/share/classes/jdk/internal/platform/Metrics.java index 50523d137ef..07d60f7f9fe 100644 --- a/src/java.base/share/classes/jdk/internal/platform/Metrics.java +++ b/src/java.base/share/classes/jdk/internal/platform/Metrics.java @@ -71,6 +71,23 @@ public static Metrics systemMetrics() { */ public String getProvider(); + /** + * Determines whether or not the underlying system + * has useful metrics (a.k.a. is containerized). + * + * @implNote + * Note that Metrics on some systems aren't useful. + * For example on a regular Linux system with cgroups + * present, with no limits enforced and not running in + * a container, Metric aren't useful. This can be used + * in order to determine if the system is containerized. + * + * @return true when the JVM runs in containerized mode. + * false otherwise. + * + */ + public boolean isContainerized(); + /* *************************************************************** * CPU Accounting Subsystem diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 60115526027..ccb82c84c92 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -370,6 +370,10 @@ private static void printSystemMetrics() { final long longRetvalNotSupported = -2; ostream.println(INDENT + "Provider: " + c.getProvider()); + if (!c.isContainerized()) { + ostream.println(INDENT + "System not containerized."); + return; + } ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount()); ostream.println(formatCpuVal(c.getCpuPeriod(), INDENT + "CPU Period: ", longRetvalNotSupported)); ostream.println(formatCpuVal(c.getCpuQuota(), INDENT + "CPU Quota: ", longRetvalNotSupported)); diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index aa1d2a19b28..0f054a3bd72 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -78,6 +78,9 @@ class TestController : public CgroupController { char* subsystem_path() override { return _path; }; + bool is_read_only() override { + return true; // doesn't matter + } }; static void fill_file(const char* path, const char* content) { @@ -436,7 +439,8 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path) { &container_engine }; for (int i = 0; i < length; i++) { CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, - (char*)testCases[i]->mount_path); + (char*)testCases[i]->mount_path, + true /* read-only mount */); ctrl->set_subsystem_path((char*)testCases[i]->cgroup_path); ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); } @@ -460,7 +464,8 @@ TEST(cgroupTest, set_cgroupv2_subsystem_path) { &sub_path }; for (int i = 0; i < length; i++) { CgroupV2Controller* ctrl = new CgroupV2Controller( (char*)testCases[i]->mount_path, - (char*)testCases[i]->cgroup_path); + (char*)testCases[i]->cgroup_path, + true /* read-only mount */); ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); } } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 254e621bfdd..0f574f7168a 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -113,7 +113,6 @@ runtime/ClassInitErrors/TestStackOverflowDuringInit.java 8334545 generic-all applications/jcstress/copy.java 8229852 linux-all -containers/cgroup/PlainRead.java 8333967,8261242 linux-all containers/docker/TestJcmd.java 8278102 linux-all containers/docker/TestMemoryAwareness.java 8303470 linux-all containers/docker/TestJFREvents.java 8327723 linux-x64 diff --git a/test/hotspot/jtreg/containers/cgroup/PlainRead.java b/test/hotspot/jtreg/containers/cgroup/TestContainerized.java similarity index 54% rename from test/hotspot/jtreg/containers/cgroup/PlainRead.java rename to test/hotspot/jtreg/containers/cgroup/TestContainerized.java index 21eccd79835..52cf5451a8d 100644 --- a/test/hotspot/jtreg/containers/cgroup/PlainRead.java +++ b/test/hotspot/jtreg/containers/cgroup/TestContainerized.java @@ -22,57 +22,27 @@ */ /* - * @test PlainRead + * @test + * @bug 8261242 * @key cgroups * @requires os.family == "linux" * @requires vm.flagless * @library /testlibrary /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI PlainRead + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestContainerized */ import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; import jdk.test.whitebox.WhiteBox; -public class PlainRead { - - static public void match(OutputAnalyzer oa, String what, String value) { - oa.shouldMatch("^.*" + what + " *" + value + ".*$"); - } - - static public void noMatch(OutputAnalyzer oa, String what, String value) { - oa.shouldNotMatch("^.*" + what + " *" + value + ".*$"); - } - - static final String good_value = "(\\d+|-1|-2|Unlimited)"; - static final String bad_value = "(failed)"; - - static final String[] variables = {"Memory Limit is:", "CPU Quota is:", "CPU Period is:", "active_processor_count:"}; - - static public void isContainer(OutputAnalyzer oa) { - for (String v: variables) { - match(oa, v, good_value); - } - for (String v: variables) { - noMatch(oa, v, bad_value); - } - } - - static public void isNotContainer(OutputAnalyzer oa) { - oa.shouldMatch("^.*Can't open /proc/self/mountinfo.*$"); - } +public class TestContainerized { public static void main(String[] args) throws Exception { WhiteBox wb = WhiteBox.getWhiteBox(); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:os+container=trace", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - if (wb.isContainerized()) { - System.out.println("Inside a cgroup, testing..."); - isContainer(output); + throw new RuntimeException("Test failed! Expected not containerized on plain Linux."); } + System.out.println("Plain linux, no limits. Passed!"); } } diff --git a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java new file mode 100644 index 00000000000..8d9279e1603 --- /dev/null +++ b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key cgroups + * @requires os.family == "linux" + * @requires vm.flagless + * @library /test/lib + * @build TestSystemSettings + * @run main/othervm TestSystemSettings + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestSystemSettings { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XshowSettings:system", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldContain("System not containerized."); + } +} diff --git a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java index a6eff3d237a..0b29d288cd9 100644 --- a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java +++ b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java @@ -69,6 +69,16 @@ private void testAll(Metrics m, boolean inContainer) throws Exception { tester.testMemoryUsage(); } tester.testMisc(); + testContainerized(m, inContainer); + } + + private void testContainerized(Metrics m, boolean inContainer) { + if (m.isContainerized() != inContainer) { + throw new RuntimeException("containerized test failed. " + + "Expected isContainerized()==" + inContainer + + " but got '" + m.isContainerized() + "'"); + } + System.out.println("testContainerized() PASSED!"); } public static void main(String[] args) throws Exception { From 747e1e47f576b0ca3ac97d1deea87418e67ff2d1 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Mon, 1 Jul 2024 10:21:31 +0000 Subject: [PATCH 41/85] 8334295: CTW: update modules Reviewed-by: shade, thartmann --- .../applications/ctw/modules/generate.bash | 4 +- .../ctw/modules/jdk_incubator_vector.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_internal_md.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_jpackage.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_nio_mapmode.java | 38 +++++++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_incubator_vector.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_internal_md.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_jpackage.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_nio_mapmode.java diff --git a/test/hotspot/jtreg/applications/ctw/modules/generate.bash b/test/hotspot/jtreg/applications/ctw/modules/generate.bash index 56e191e7af1..935503484b9 100644 --- a/test/hotspot/jtreg/applications/ctw/modules/generate.bash +++ b/test/hotspot/jtreg/applications/ctw/modules/generate.bash @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ do echo creating $file for $module... cat > $file < Date: Mon, 1 Jul 2024 11:51:13 +0000 Subject: [PATCH 42/85] 8335060: ClassCastException after JDK-8294960 Reviewed-by: liach, jpai --- .../invoke/TypeConvertingMethodAdapter.java | 16 +- .../java/lang/invoke/TypeConvertingTest.java | 798 ++++++++++++++++++ 2 files changed, 806 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/lang/invoke/TypeConvertingTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java index e35271dc8b4..7a1419f03b1 100644 --- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java +++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -69,14 +69,14 @@ private static MethodRefEntry unbox(ClassDesc owner, String methodName, ClassDes } private static TypeKind primitiveTypeKindFromClass(Class type) { - if (type == int.class) return TypeKind.IntType; - if (type == long.class) return TypeKind.LongType; - if (type == boolean.class) return TypeKind.BooleanType; - if (type == short.class) return TypeKind.ShortType; - if (type == byte.class) return TypeKind.ByteType; - if (type == char.class) return TypeKind.CharType; - if (type == float.class) return TypeKind.FloatType; - if (type == double.class) return TypeKind.DoubleType; + if (type == Integer.class) return TypeKind.IntType; + if (type == Long.class) return TypeKind.LongType; + if (type == Boolean.class) return TypeKind.BooleanType; + if (type == Short.class) return TypeKind.ShortType; + if (type == Byte.class) return TypeKind.ByteType; + if (type == Character.class) return TypeKind.CharType; + if (type == Float.class) return TypeKind.FloatType; + if (type == Double.class) return TypeKind.DoubleType; return null; } diff --git a/test/jdk/java/lang/invoke/TypeConvertingTest.java b/test/jdk/java/lang/invoke/TypeConvertingTest.java new file mode 100644 index 00000000000..1df6e007880 --- /dev/null +++ b/test/jdk/java/lang/invoke/TypeConvertingTest.java @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/* @test + * @bug 8335060 + * @summary unit tests of TypeConvertingMethodAdapter + * @run junit TypeConvertingTest + */ +public class TypeConvertingTest { + + static void smallBooleanC(boolean b) { + assertTrue(b); + } + + static void bigBooleanC(Boolean b) { + assertTrue(b); + } + + static void smallByteC(byte b) { + assertEquals(1, b); + } + + static void bigByteC(Byte b) { + assertEquals((byte)1, b); + } + + static void smallShortC(short s) { + assertEquals(1, s); + } + + static void bigShortC(Short s) { + assertEquals((short)1, s); + } + + static void smallCharC(char c) { + assertEquals(1, c); + } + + static void bigCharC(Character c) { + assertEquals((char)1, c); + } + + static void smallIntC(int i) { + assertEquals(1, i); + } + + static void bigIntC(Integer i) { + assertEquals(1, i); + } + + static void smallLongC(long l) { + assertEquals(1, l); + } + + static void bigLongC(Long l) { + assertEquals(1, l); + } + + static void smallFloatC(float f) { + assertEquals(1.0f, f); + } + + static void bigFloatC(Float f) { + assertEquals(1.0f, f); + } + + static void smallDoubleC(double d) { + assertEquals(1.0, d); + } + + static void bigDoubleC(Double d) { + assertEquals(1.0, d); + } + + static void numberC(Number n) { + assertEquals(1, n.intValue()); + } + + + static boolean smallBooleanS() {return true;} + + static Boolean bigBooleanS() {return true;} + + static byte smallByteS() {return 1;} + + static Byte bigByteS() {return 1;} + + static short smallShortS() {return 1;} + + static Short bigShortS() {return 1;} + + static char smallCharS() {return 1;} + + static Character bigCharS() {return 1;} + + static int smallIntS() {return 1;} + + static Integer bigIntS() {return 1;} + + static long smallLongS() {return 1;} + + static Long bigLongS() {return 1l;} + + static float smallFloatS() {return 1;} + + static Float bigFloatS() {return 1f;} + + static double smallDoubleS() {return 1;} + + static Double bigDoubleS() {return 1d;} + + static Number numberS() {return 1;} + + + interface GenericC { + void m(T t); + } + + interface SmallBooleanC { + void m(boolean b); + } + + interface BigBooleanC { + void m(Boolean b); + } + + interface SmallByteC { + void m(byte b); + } + + interface BigByteC { + void m(Byte b); + } + + interface SmallShortC { + void m(short s); + } + + interface BigShortC { + void m(Short s); + } + + interface SmallCharC { + void m(char c); + } + + interface BigCharC { + void m(Character c); + } + + interface SmallIntC { + void m(int i); + } + + interface BigIntC { + void m(Integer i); + } + + interface SmallLongC { + void m(long l); + } + + interface BigLongC { + void m(Long l); + } + + interface SmallFloatC { + void m(float f); + } + + interface BigFloatC { + void m(Float f); + } + + interface SmallDoubleC { + void m(double d); + } + + interface BigDoubleC { + void m(Double d); + } + + interface BigNumberC { + void m(Number n); + } + + + interface GenericS { + T m(); + } + + interface SmallBooleanS { + boolean m(); + } + + interface BigBooleanS { + Boolean m(); + } + + interface SmallByteS { + byte m(); + } + + interface BigByteS { + Byte m(); + } + + interface SmallShortS { + short m(); + } + + interface BigShortS { + Short m(); + } + + interface SmallCharS { + char m(); + } + + interface BigCharS { + Character m(); + } + + interface SmallIntS { + int m(); + } + + interface BigIntS { + Integer m(); + } + + interface SmallLongS { + long m(); + } + + interface BigLongS { + Long m(); + } + + interface SmallFloatS { + float m(); + } + + interface BigFloatS { + Float m(); + } + + interface SmallDoubleS { + double m(); + } + + interface BigDoubleS { + Double m(); + } + + interface BigNumberS { + Number m(); + } + + + static void testGenericBoolean(GenericC t) { + t.m(true); + } + + static void testGenericByte(GenericC t) { + t.m((byte)1); + } + + static void testGenericShort(GenericC t) { + t.m((short)1); + } + + static void testGenericChar(GenericC t) { + t.m((char)1); + } + + static void testGenericInt(GenericC t) { + t.m(1); + } + + static void testGenericLong(GenericC t) { + t.m(1l); + } + + static void testGenericFloat(GenericC t) { + t.m(1.0f); + } + + static void testGenericDouble(GenericC t) { + t.m(1.0d); + } + + static void testGenericNumber(GenericC t) { + t.m(1); + } + + static void testSmallBoolean(SmallBooleanC t) { + t.m(true); + } + + static void testSmallByte(SmallByteC t) { + t.m((byte)1); + } + + static void testSmallShort(SmallShortC t) { + t.m((short)1); + } + + static void testSmallChar(SmallCharC t) { + t.m((char)1); + } + + static void testSmallInt(SmallIntC t) { + t.m(1); + } + + static void testSmallLong(SmallLongC t) { + t.m(1l); + } + + static void testSmallFloat(SmallFloatC t) { + t.m(1.0f); + } + + static void testSmallDouble(SmallDoubleC t) { + t.m(1.0d); + } + + static void testBigBoolean(BigBooleanC t) { + t.m(true); + } + + static void testBigByte(BigByteC t) { + t.m((byte)1); + } + + static void testBigShort(BigShortC t) { + t.m((short)1); + } + + static void testBigChar(BigCharC t) { + t.m((char)1); + } + + static void testBigInt(BigIntC t) { + t.m(1); + } + + static void testBigLong(BigLongC t) { + t.m(1l); + } + + static void testBigFloat(BigFloatC t) { + t.m(1.0f); + } + + static void testBigDouble(BigDoubleC t) { + t.m(1.0d); + } + + static void testBigNumber(BigNumberC t) { + t.m(1); + } + + + static void testGenericBoolean(GenericS t) { + assertEquals(true, t.m()); + } + + static void testGenericByte(GenericS t) { + assertEquals((byte)1, t.m()); + } + + static void testGenericShort(GenericS t) { + assertEquals((short)1, t.m()); + } + + static void testGenericChar(GenericS t) { + assertEquals((char)1, t.m()); + } + + static void testGenericInt(GenericS t) { + assertEquals(1, t.m()); + } + + static void testGenericLong(GenericS t) { + assertEquals(1, t.m()); + } + + static void testGenericFloat(GenericS t) { + assertEquals(1.0f, t.m()); + } + + static void testGenericDouble(GenericS t) { + assertEquals(1.0d, t.m()); + } + + static void testGenericNumber(GenericS t) { + assertEquals(1, t.m().intValue()); + } + + static void testSmallBoolean(SmallBooleanS t) { + assertEquals(true, t.m()); + } + + static void testSmallByte(SmallByteS t) { + assertEquals(1, t.m()); + } + + static void testSmallShort(SmallShortS t) { + assertEquals(1, t.m()); + } + + static void testSmallChar(SmallCharS t) { + assertEquals(1, t.m()); + } + + static void testSmallInt(SmallIntS t) { + assertEquals(1, t.m()); + } + + static void testSmallLong(SmallLongS t) { + assertEquals(1, t.m()); + } + + static void testSmallFloat(SmallFloatS t) { + assertEquals(1.0f, t.m()); + } + + static void testSmallDouble(SmallDoubleS t) { + assertEquals(1.0d, t.m()); + } + + static void testBigBoolean(BigBooleanS t) { + assertEquals(true, t.m()); + } + + static void testBigByte(BigByteS t) { + assertEquals((byte)1, t.m()); + } + + static void testBigShort(BigShortS t) { + assertEquals((short)1, t.m()); + } + + static void testBigChar(BigCharS t) { + assertEquals((char)1, t.m()); + } + + static void testBigInt(BigIntS t) { + assertEquals(1, t.m()); + } + + static void testBigLong(BigLongS t) { + assertEquals(1, t.m()); + } + + static void testBigFloat(BigFloatS t) { + assertEquals(1.0f, t.m()); + } + + static void testBigDouble(BigDoubleS t) { + assertEquals(1.0f, t.m()); + } + + static void testBigNumber(BigNumberS t) { + assertEquals(1, t.m().intValue()); + } + + + @Test + void testGenericBoolean() { + testGenericBoolean(TypeConvertingTest::smallBooleanC); + testGenericBoolean(TypeConvertingTest::bigBooleanC); + + testGenericBoolean(TypeConvertingTest::smallBooleanS); + testGenericBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testGenericByte() { + testGenericByte(TypeConvertingTest::smallByteC); + testGenericByte(TypeConvertingTest::bigByteC); + testGenericByte(TypeConvertingTest::smallShortC); + testGenericByte(TypeConvertingTest::smallIntC); + testGenericByte(TypeConvertingTest::smallLongC); + testGenericByte(TypeConvertingTest::smallFloatC); + testGenericByte(TypeConvertingTest::smallDoubleC); + testGenericByte(TypeConvertingTest::numberC); + + testGenericByte(TypeConvertingTest::smallByteS); + testGenericByte(TypeConvertingTest::bigByteS); + } + + @Test + void testGenericShort() { + testGenericShort(TypeConvertingTest::smallShortC); + testGenericShort(TypeConvertingTest::bigShortC); + testGenericShort(TypeConvertingTest::smallIntC); + testGenericShort(TypeConvertingTest::smallLongC); + testGenericShort(TypeConvertingTest::smallFloatC); + testGenericShort(TypeConvertingTest::smallDoubleC); + testGenericShort(TypeConvertingTest::numberC); + + testGenericShort(TypeConvertingTest::smallShortS); + testGenericShort(TypeConvertingTest::bigShortS); + } + + @Test + void testGenericChar() { + testGenericChar(TypeConvertingTest::smallCharC); + testGenericChar(TypeConvertingTest::bigCharC); + testGenericChar(TypeConvertingTest::smallIntC); + testGenericChar(TypeConvertingTest::smallLongC); + testGenericChar(TypeConvertingTest::smallFloatC); + testGenericChar(TypeConvertingTest::smallDoubleC); + + testGenericChar(TypeConvertingTest::smallCharS); + testGenericChar(TypeConvertingTest::bigCharS); + } + + @Test + void testGenericInt() { + testGenericInt(TypeConvertingTest::smallIntC); + testGenericInt(TypeConvertingTest::bigIntC); + testGenericInt(TypeConvertingTest::smallLongC); + testGenericInt(TypeConvertingTest::smallFloatC); + testGenericInt(TypeConvertingTest::smallDoubleC); + testGenericInt(TypeConvertingTest::numberC); + + testGenericInt(TypeConvertingTest::smallIntS); + testGenericInt(TypeConvertingTest::bigIntS); + } + + @Test + void testGenericLong() { + testGenericLong(TypeConvertingTest::smallLongC); + testGenericLong(TypeConvertingTest::bigLongC); + testGenericLong(TypeConvertingTest::smallFloatC); + testGenericLong(TypeConvertingTest::smallDoubleC); + testGenericLong(TypeConvertingTest::numberC); + + testGenericLong(TypeConvertingTest::smallLongS); + testGenericLong(TypeConvertingTest::bigLongS); + } + + @Test + void testGenericFloat() { + testGenericFloat(TypeConvertingTest::smallFloatC); + testGenericFloat(TypeConvertingTest::bigFloatC); + testGenericFloat(TypeConvertingTest::smallDoubleC); + testGenericFloat(TypeConvertingTest::numberC); + + testGenericFloat(TypeConvertingTest::smallFloatS); + testGenericFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testGenericDouble() { + testGenericDouble(TypeConvertingTest::smallDoubleC); + testGenericDouble(TypeConvertingTest::bigDoubleC); + testGenericDouble(TypeConvertingTest::numberC); + + testGenericDouble(TypeConvertingTest::smallDoubleS); + testGenericDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testGenericNumber() { + testGenericNumber(TypeConvertingTest::numberC); + + testGenericNumber(TypeConvertingTest::numberS); + } + + @Test + void testSmallBoolean() { + testSmallBoolean(TypeConvertingTest::smallBooleanC); + testSmallBoolean(TypeConvertingTest::bigBooleanC); + + testSmallBoolean(TypeConvertingTest::smallBooleanS); + testSmallBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testSmallByte() { + testSmallByte(TypeConvertingTest::smallByteC); + testSmallByte(TypeConvertingTest::bigByteC); + testSmallByte(TypeConvertingTest::smallShortC); + testSmallByte(TypeConvertingTest::smallIntC); + testSmallByte(TypeConvertingTest::smallLongC); + testSmallByte(TypeConvertingTest::smallFloatC); + testSmallByte(TypeConvertingTest::smallDoubleC); + testSmallByte(TypeConvertingTest::numberC); + + testSmallByte(TypeConvertingTest::smallByteS); + testSmallByte(TypeConvertingTest::bigByteS); + } + + @Test + void testSmallShort() { + testSmallShort(TypeConvertingTest::smallShortC); + testSmallShort(TypeConvertingTest::bigShortC); + testSmallShort(TypeConvertingTest::smallIntC); + testSmallShort(TypeConvertingTest::smallLongC); + testSmallShort(TypeConvertingTest::smallFloatC); + testSmallShort(TypeConvertingTest::smallDoubleC); + testSmallShort(TypeConvertingTest::numberC); + + testSmallShort(TypeConvertingTest::smallShortS); + testSmallShort(TypeConvertingTest::bigShortS); + } + + @Test + void testSmallChar() { + testSmallChar(TypeConvertingTest::smallCharC); + testSmallChar(TypeConvertingTest::bigCharC); + testSmallChar(TypeConvertingTest::smallIntC); + testSmallChar(TypeConvertingTest::smallLongC); + testSmallChar(TypeConvertingTest::smallFloatC); + testSmallChar(TypeConvertingTest::smallDoubleC); + + testSmallChar(TypeConvertingTest::smallCharS); + testSmallChar(TypeConvertingTest::bigCharS); + } + + @Test + void testSmallInt() { + testSmallInt(TypeConvertingTest::smallIntC); + testSmallInt(TypeConvertingTest::bigIntC); + testSmallInt(TypeConvertingTest::smallLongC); + testSmallInt(TypeConvertingTest::smallFloatC); + testSmallInt(TypeConvertingTest::smallDoubleC); + testSmallInt(TypeConvertingTest::numberC); + + testSmallInt(TypeConvertingTest::smallIntS); + testSmallInt(TypeConvertingTest::bigIntS); + } + + @Test + void testSmallLong() { + testSmallLong(TypeConvertingTest::smallLongC); + testSmallLong(TypeConvertingTest::bigLongC); + testSmallLong(TypeConvertingTest::smallFloatC); + testSmallLong(TypeConvertingTest::smallDoubleC); + testSmallLong(TypeConvertingTest::numberC); + + testSmallLong(TypeConvertingTest::smallLongS); + testSmallLong(TypeConvertingTest::bigLongS); + } + + @Test + void testSmallFloat() { + testSmallFloat(TypeConvertingTest::smallFloatC); + testSmallFloat(TypeConvertingTest::bigFloatC); + testSmallFloat(TypeConvertingTest::smallDoubleC); + testSmallFloat(TypeConvertingTest::numberC); + + testSmallFloat(TypeConvertingTest::smallFloatS); + testSmallFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testSmallDouble() { + testSmallDouble(TypeConvertingTest::smallDoubleC); + testSmallDouble(TypeConvertingTest::bigDoubleC); + testSmallDouble(TypeConvertingTest::numberC); + + testSmallDouble(TypeConvertingTest::smallDoubleS); + testSmallDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testBigBoolean() { + testBigBoolean(TypeConvertingTest::smallBooleanC); + testBigBoolean(TypeConvertingTest::bigBooleanC); + + testBigBoolean(TypeConvertingTest::smallBooleanS); + testBigBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testBigByte() { + testBigByte(TypeConvertingTest::smallByteC); + testBigByte(TypeConvertingTest::bigByteC); + testBigByte(TypeConvertingTest::smallShortC); + testBigByte(TypeConvertingTest::smallIntC); + testBigByte(TypeConvertingTest::smallLongC); + testBigByte(TypeConvertingTest::smallFloatC); + testBigByte(TypeConvertingTest::smallDoubleC); + testBigByte(TypeConvertingTest::numberC); + + testBigByte(TypeConvertingTest::smallByteS); + testBigByte(TypeConvertingTest::bigByteS); + } + + @Test + void testBigShort() { + testBigShort(TypeConvertingTest::smallShortC); + testBigShort(TypeConvertingTest::bigShortC); + testBigShort(TypeConvertingTest::smallIntC); + testBigShort(TypeConvertingTest::smallLongC); + testBigShort(TypeConvertingTest::smallFloatC); + testBigShort(TypeConvertingTest::smallDoubleC); + testBigShort(TypeConvertingTest::numberC); + + testBigShort(TypeConvertingTest::smallShortS); + testBigShort(TypeConvertingTest::bigShortS); + } + + @Test + void testBigChar() { + testBigChar(TypeConvertingTest::smallCharC); + testBigChar(TypeConvertingTest::bigCharC); + testBigChar(TypeConvertingTest::smallIntC); + testBigChar(TypeConvertingTest::smallLongC); + testBigChar(TypeConvertingTest::smallFloatC); + testBigChar(TypeConvertingTest::smallDoubleC); + + testBigChar(TypeConvertingTest::smallCharS); + testBigChar(TypeConvertingTest::bigCharS); + } + + @Test + void testBigInt() { + testBigInt(TypeConvertingTest::smallIntC); + testBigInt(TypeConvertingTest::bigIntC); + testBigInt(TypeConvertingTest::smallLongC); + testBigInt(TypeConvertingTest::smallFloatC); + testBigInt(TypeConvertingTest::smallDoubleC); + testBigInt(TypeConvertingTest::numberC); + + testBigInt(TypeConvertingTest::smallIntS); + testBigInt(TypeConvertingTest::bigIntS); + } + + @Test + void testBigLong() { + testBigLong(TypeConvertingTest::smallLongC); + testBigLong(TypeConvertingTest::bigLongC); + testBigLong(TypeConvertingTest::smallFloatC); + testBigLong(TypeConvertingTest::smallDoubleC); + testBigLong(TypeConvertingTest::numberC); + + testBigLong(TypeConvertingTest::smallLongS); + testBigLong(TypeConvertingTest::bigLongS); + } + + @Test + void testBigFloat() { + testBigFloat(TypeConvertingTest::smallFloatC); + testBigFloat(TypeConvertingTest::bigFloatC); + testBigFloat(TypeConvertingTest::smallDoubleC); + testBigFloat(TypeConvertingTest::numberC); + + testBigFloat(TypeConvertingTest::smallFloatS); + testBigFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testBigDouble() { + testBigDouble(TypeConvertingTest::smallDoubleC); + testBigDouble(TypeConvertingTest::bigDoubleC); + testBigDouble(TypeConvertingTest::numberC); + + testBigDouble(TypeConvertingTest::smallDoubleS); + testBigDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testBigNumber() { + testBigNumber(TypeConvertingTest::numberC); + + testBigNumber(TypeConvertingTest::numberS); + } +} From 2f4f6cc34c10c5519c74abbce8d1715013b50d5d Mon Sep 17 00:00:00 2001 From: Arseny Bochkarev Date: Mon, 1 Jul 2024 12:19:49 +0000 Subject: [PATCH 43/85] 8317721: RISC-V: Implement CRC32 intrinsic Reviewed-by: vkempik, rehn --- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 17 +- .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 74 +++++- .../cpu/riscv/macroAssembler_riscv.cpp | 169 +++++++++++++ .../cpu/riscv/macroAssembler_riscv.hpp | 10 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 52 ++++ src/hotspot/cpu/riscv/stubRoutines_riscv.cpp | 222 ++++++++++++++++++ src/hotspot/cpu/riscv/stubRoutines_riscv.hpp | 3 + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 10 +- 8 files changed, 553 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 9804eee61ff..b2489268611 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1607,7 +1607,22 @@ void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } -void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { Unimplemented(); } +void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { + assert(op->crc()->is_single_cpu(), "crc must be register"); + assert(op->val()->is_single_cpu(), "byte value must be register"); + assert(op->result_opr()->is_single_cpu(), "result must be register"); + Register crc = op->crc()->as_register(); + Register val = op->val()->as_register(); + Register res = op->result_opr()->as_register(); + + assert_different_registers(val, crc, res); + __ la(res, ExternalAddress(StubRoutines::crc_table_addr())); + + __ notr(crc, crc); // ~crc + __ zero_extend(crc, crc, 32); + __ update_byte_crc32(crc, val, res); + __ notr(res, crc); // ~crc +} void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass, Register tmp, Label &next, Label &none, diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index 8017c0fc802..409e8dc0a0d 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -781,7 +781,79 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { } void LIRGenerator::do_update_CRC32(Intrinsic* x) { - ShouldNotReachHere(); + assert(UseCRC32Intrinsics, "why are we here?"); + // Make all state_for calls early since they can emit code + LIR_Opr result = rlock_result(x); + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); + LIRItem val(x->argument_at(1), this); + // val is destroyed by update_crc32 + val.set_destroys_register(); + crc.load_item(); + val.load_item(); + __ update_crc32(crc.result(), val.result(), result); + break; + } + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: { + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem len(x->argument_at(3), this); + buf.load_item(); + off.load_nonconstant(); + + LIR_Opr index = off.result(); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if (off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + } + + if (offset) { + LIR_Opr tmp = new_pointer_register(); + __ add(base_op, LIR_OprFact::intConst(offset), tmp); + base_op = tmp; + offset = 0; + } + + LIR_Address* a = new LIR_Address(base_op, + index, + offset, + T_BYTE); + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr addr = new_pointer_register(); + __ leal(LIR_OprFact::address(a), addr); + + crc.load_item_force(cc->at(0)); + __ move(addr, cc->at(1)); + len.load_item_force(cc->at(2)); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), getThreadTemp(), result_reg, cc->args()); + __ move(result_reg, result); + + break; + } + default: { + ShouldNotReachHere(); + } + } } void LIRGenerator::do_update_CRC32C(Intrinsic* x) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 0e6a9099265..b707b20f669 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1428,6 +1428,175 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { return count; } +static const int64_t right_32_bits = right_n_bits(32); +static const int64_t right_8_bits = right_n_bits(8); + +/** + * Emits code to update CRC-32 with a byte value according to constants in table + * + * @param [in,out]crc Register containing the crc. + * @param [in]val Register containing the byte to fold into the CRC. + * @param [in]table Register containing the table of crc constants. + * + * uint32_t crc; + * val = crc_table[(val ^ crc) & 0xFF]; + * crc = val ^ (crc >> 8); + * + */ +void MacroAssembler::update_byte_crc32(Register crc, Register val, Register table) { + assert_different_registers(crc, val, table); + + xorr(val, val, crc); + andi(val, val, right_8_bits); + shadd(val, val, table, val, 2); + lwu(val, Address(val)); + srli(crc, crc, 8); + xorr(crc, val, crc); +} + +/** + * Emits code to update CRC-32 with a 32-bit value according to tables 0 to 3 + * + * @param [in,out]crc Register containing the crc. + * @param [in]v Register containing the 32-bit to fold into the CRC. + * @param [in]table0 Register containing table 0 of crc constants. + * @param [in]table1 Register containing table 1 of crc constants. + * @param [in]table2 Register containing table 2 of crc constants. + * @param [in]table3 Register containing table 3 of crc constants. + * + * uint32_t crc; + * v = crc ^ v + * crc = table3[v&0xff]^table2[(v>>8)&0xff]^table1[(v>>16)&0xff]^table0[v>>24] + * + */ +void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1, Register tmp2, Register tmp3, + Register table0, Register table1, Register table2, Register table3, bool upper) { + assert_different_registers(crc, v, tmp1, tmp2, tmp3, table0, table1, table2, table3); + + if (upper) + srli(v, v, 32); + xorr(v, v, crc); + + andi(tmp1, v, right_8_bits); + shadd(tmp1, tmp1, table3, tmp2, 2); + lwu(crc, Address(tmp1)); + + slli(tmp1, v, 16); + slli(tmp3, v, 8); + + srliw(tmp1, tmp1, 24); + srliw(tmp3, tmp3, 24); + + shadd(tmp1, tmp1, table2, tmp1, 2); + lwu(tmp2, Address(tmp1)); + + shadd(tmp3, tmp3, table1, tmp3, 2); + xorr(crc, crc, tmp2); + + lwu(tmp2, Address(tmp3)); + if (upper) { + tmp1 = v; + srli(tmp1, v, 24); + } + else + srliw(tmp1, v, 24); + + // no need to clear bits other than lowest two + shadd(tmp1, tmp1, table0, tmp1, 2); + xorr(crc, crc, tmp2); + lwu(tmp2, Address(tmp1)); + xorr(crc, crc, tmp2); +} + +/** + * @param crc register containing existing CRC (32-bit) + * @param buf register pointing to input byte buffer (byte*) + * @param len register containing number of bytes + * @param table register that will contain address of CRC table + * @param tmp scratch registers + */ +void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, + Register table0, Register table1, Register table2, Register table3, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) { + assert_different_registers(crc, buf, len, table0, table1, table2, table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + Label L_by16_loop, L_unroll_loop, L_unroll_loop_entry, L_by4, L_by4_loop, L_by1, L_by1_loop, L_exit; + + const int64_t unroll = 16; + const int64_t unroll_words = unroll*wordSize; + mv(tmp5, right_32_bits); + subw(len, len, unroll_words); + andn(crc, tmp5, crc); + + const ExternalAddress table_addr = StubRoutines::crc_table_addr(); + la(table0, table_addr); + add(table1, table0, 1*256*sizeof(juint), tmp1); + add(table2, table0, 2*256*sizeof(juint), tmp1); + add(table3, table2, 1*256*sizeof(juint), tmp1); + + bge(len, zr, L_unroll_loop_entry); + addiw(len, len, unroll_words-4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + bgt(len, zr, L_by1_loop); + j(L_exit); + + align(CodeEntryAlignment); + bind(L_unroll_loop_entry); + const Register buf_end = tmp3; + add(buf_end, buf, len); // buf_end will be used as endpoint for loop below + andi(len, len, unroll_words-1); // len = (len % unroll_words) + sub(len, len, unroll_words); // Length after all iterations + bind(L_unroll_loop); + for (int i = 0; i < unroll; i++) { + ld(tmp1, Address(buf, i*wordSize)); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, true); + } + + addi(buf, buf, unroll_words); + ble(buf, buf_end, L_unroll_loop); + addiw(len, len, unroll_words-4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + bgt(len, zr, L_by1_loop); + j(L_exit); + + bind(L_by4_loop); + lwu(tmp1, Address(buf)); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false); + subw(len, len, 4); + addi(buf, buf, 4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + ble(len, zr, L_exit); + + bind(L_by1_loop); + subw(len, len, 1); + lwu(tmp1, Address(buf)); + andi(tmp2, tmp1, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + subw(len, len, 1); + srli(tmp2, tmp1, 8); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + subw(len, len, 1); + srli(tmp2, tmp1, 16); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + srli(tmp2, tmp1, 24); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + + bind(L_exit); + andn(crc, tmp5, crc); +} + #ifdef COMPILER2 // Push vector registers in the bitset supplied. // Return the number of words pushed diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 4373ebada14..ddd3c48a93e 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1288,6 +1288,15 @@ class MacroAssembler: public Assembler { void compute_match_mask(Register src, Register pattern, Register match_mask, Register mask1, Register mask2); + // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. + void kernel_crc32(Register crc, Register buf, Register len, + Register table0, Register table1, Register table2, Register table3, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6); + void update_word_crc32(Register crc, Register v, Register tmp1, Register tmp2, Register tmp3, + Register table0, Register table1, Register table2, Register table3, + bool upper); + void update_byte_crc32(Register crc, Register val, Register table); + #ifdef COMPILER2 void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp); @@ -1317,6 +1326,7 @@ class MacroAssembler: public Assembler { Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi); + #endif void inflate_lo32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 3a34e87c140..61c7a8668f5 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5313,6 +5313,52 @@ static const int64_t right_3_bits = right_n_bits(3); #endif // COMPILER2 + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - int length + * + * Output: + * c_rarg0 - int crc result + */ + address generate_updateBytesCRC32() { + assert(UseCRC32Intrinsics, "what are we doing here?"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32"); + + address start = __ pc(); + + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register table0 = c_rarg3; // crc_table address + const Register table1 = c_rarg4; + const Register table2 = c_rarg5; + const Register table3 = c_rarg6; + + const Register tmp1 = c_rarg7; + const Register tmp2 = t2; + const Register tmp3 = x28; // t3 + const Register tmp4 = x29; // t4 + const Register tmp5 = x30; // t5 + const Register tmp6 = x31; // t6 + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ kernel_crc32(crc, buf, len, table0, table1, table2, + table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(); + + return start; + } + #if INCLUDE_JFR static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { @@ -5559,6 +5605,12 @@ static const int64_t right_3_bits = right_n_bits(3); generate_throw_exception("delayed StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); + + if (UseCRC32Intrinsics) { + // set table address before stub generation which use it + StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table; + StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); + } } void generate_continuation_stubs() { diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index 39068a9a026..05bdeaf7570 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -55,3 +55,225 @@ address StubRoutines::riscv::_string_indexof_linear_ul = nullptr; address StubRoutines::riscv::_large_byte_array_inflate = nullptr; bool StubRoutines::riscv::_completed = false; + +/** + * crc_table[] from jdk/src/java.base/share/native/libzip/zlib/crc32.h + */ +ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] = +{ + // Table 0 + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL, + + // Table 1 + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL, + + // Table 2 + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL, + + // Table 3 + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL, +}; diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp index 90a7e0967b2..46b5461d777 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -153,6 +153,9 @@ class riscv { static void set_completed() { _completed = true; } + +private: + static juint _crc_table[]; }; #endif // CPU_RISCV_STUBROUTINES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index b9467bb2245..b7517bc3f3f 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -131,8 +131,14 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } - if (UseCRC32Intrinsics) { - warning("CRC32 intrinsics are not available on this CPU."); + if (UseZba) { + if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { + FLAG_SET_DEFAULT(UseCRC32Intrinsics, true); + } + } else { + if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { + warning("CRC32 intrinsic requires Zba instructions (not available on this CPU)"); + } FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } From ee4720a75d815c84039055902c88b360737a1f9c Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 1 Jul 2024 20:38:55 +0000 Subject: [PATCH 44/85] 8333306: gc/arguments/TestParallelGCErgo.java fails when largepage are enabled Reviewed-by: ayang, zgu --- test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java index a84ebc5fe5c..63c51c25149 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java @@ -27,6 +27,7 @@ * @test TestParallelGCErgo * @bug 8272364 * @requires vm.gc.Parallel + * @requires vm.opt.UseLargePages == null | !vm.opt.UseLargePages * @summary Verify ParallelGC minimum young and old ergonomics are setup correctly * @modules java.base/jdk.internal.misc * @library /test/lib From 5fe07b36d9eb296661692d903ed0b9b5afefba0f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 2 Jul 2024 03:39:43 +0000 Subject: [PATCH 45/85] 5021949: JSplitPane setEnabled(false) shouldn't be partially functional Reviewed-by: abhiscxk, achung, aivanov --- .../share/classes/javax/swing/JSplitPane.java | 14 ++- .../plaf/basic/BasicSplitPaneDivider.java | 16 +++ .../JSplitPane/TestSplitPaneEnableTest.java | 109 ++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JSplitPane.java b/src/java.desktop/share/classes/javax/swing/JSplitPane.java index 14f62565d40..7d4482af07e 100644 --- a/src/java.desktop/share/classes/javax/swing/JSplitPane.java +++ b/src/java.desktop/share/classes/javax/swing/JSplitPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.plaf.SplitPaneUI; +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * JSplitPane is used to divide two (and only two) @@ -361,6 +362,17 @@ public JSplitPane(int newOrientation, } + /** + * {@inheritDoc} + * @param enabled {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (this.getUI() instanceof BasicSplitPaneUI) { + ((BasicSplitPaneUI)(this.getUI())).getDivider().setEnabled(enabled); + } + } /** * Sets the L&F object that renders this component. diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java index 3018de4fd93..188e6753887 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -360,6 +360,20 @@ else if (e.getPropertyName() == JSplitPane. } } + /** + * {@inheritDoc} + * @param enabled {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + if (splitPane.isOneTouchExpandable() && + rightButton != null && + leftButton != null) { + + rightButton.setEnabled(enabled); + leftButton.setEnabled(enabled); + } + } /** * Paints the divider. @@ -472,6 +486,7 @@ public boolean isFocusTraversable() { b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); + b.setEnabled(splitPane.isEnabled()); return b; } @@ -529,6 +544,7 @@ public boolean isFocusTraversable() { b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); + b.setEnabled(splitPane.isEnabled()); return b; } diff --git a/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java b/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java new file mode 100644 index 00000000000..0172e4b5242 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5021949 + * @summary Verifies JSplitPane setEnabled(false) disables one touch expandable clicks + * @run main TestSplitPaneEnableTest + */ + +import java.awt.Point; +import java.awt.event.InputEvent; +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class TestSplitPaneEnableTest { + private static JButton leftOneTouchButton; + private static JButton rightOneTouchButton; + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + if (laf.getClassName().toLowerCase().contains("gtk")) { + continue; + } + System.out.println("Testing LAF : " + laf.getClassName()); + + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JButton("Left"), new JButton("Right")); + jsp.setUI(new TestSplitPaneUI()); + jsp.setOneTouchExpandable(true); + jsp.setEnabled(false); + if (leftOneTouchButton.isEnabled()) { + throw new RuntimeException("leftButton is enabled for disabled JSplitPane"); + } + if (rightOneTouchButton.isEnabled()) { + throw new RuntimeException("rightButton is enabled for disabled JSplitPane"); + } + + }); + } + } + + static class TestSplitPaneUI extends BasicSplitPaneUI { + + public TestSplitPaneUI() { + super(); + } + + public BasicSplitPaneDivider createDefaultDivider() { + return new TestSplitPaneDivider(this); + } + } + + static class TestSplitPaneDivider extends BasicSplitPaneDivider { + + public TestSplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + } + + protected JButton createLeftOneTouchButton() { + leftOneTouchButton = super.createLeftOneTouchButton(); + return leftOneTouchButton; + } + + protected JButton createRightOneTouchButton() { + rightOneTouchButton = super.createRightOneTouchButton(); + return rightOneTouchButton; + } + } +} + From 318d9acadf305f9d7d0cd8bb54b41506dd9914a8 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Jul 2024 05:56:21 +0000 Subject: [PATCH 46/85] 8335369: Fix -Wzero-as-null-pointer-constant warnings in ImmutableOopMapBuilder Reviewed-by: kvn, jwaters --- src/hotspot/share/compiler/oopMap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 80832cdacd4..634fb8b0bfa 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -411,7 +411,7 @@ class ImmutableOopMapBuilder { Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(nullptr) {} - void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + void set(kind_t kind, int offset, int size, const OopMap* map, const OopMap* other = nullptr) { _kind = kind; _offset = offset; _size = size; From 9046d7aee3082b6cbf79876efc1c508cb893caad Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 2 Jul 2024 08:20:26 +0000 Subject: [PATCH 47/85] 8335390: C2 MergeStores: wrong result with Unsafe Reviewed-by: thartmann, chagedorn, kvn --- src/hotspot/share/opto/memnode.cpp | 7 +- .../jtreg/compiler/c2/TestMergeStores.java | 5 +- .../c2/TestMergeStoresUnsafeArrayPointer.java | 132 ++++++++++++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index d0b6c59637f..ad3a948793f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2984,6 +2984,9 @@ StoreNode* MergePrimitiveArrayStores::run() { type2aelembytes(bt) != _store->memory_size()) { return nullptr; } + if (_store->is_unsafe_access()) { + return nullptr; + } // The _store must be the "last" store in a chain. If we find a use we could merge with // then that use or a store further down is the "last" store. @@ -3017,11 +3020,13 @@ bool MergePrimitiveArrayStores::is_compatible_store(const StoreNode* other_store int opc = _store->Opcode(); assert(opc == Op_StoreB || opc == Op_StoreC || opc == Op_StoreI, "precondition"); assert(_store->adr_type()->isa_aryptr() != nullptr, "must be array store"); + assert(!_store->is_unsafe_access(), "no unsafe accesses"); if (other_store == nullptr || _store->Opcode() != other_store->Opcode() || other_store->adr_type() == nullptr || - other_store->adr_type()->isa_aryptr() == nullptr) { + other_store->adr_type()->isa_aryptr() == nullptr || + other_store->is_unsafe_access()) { return false; } diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 0e86045618b..a94004d8e26 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -611,8 +611,9 @@ static Object[] test1e(byte[] a) { } @Test - @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, - applyIf = {"UseUnalignedAccesses", "true"}) + // Disabled by JDK-8335390, to be enabled again by JDK-8335392. + // @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, + // applyIf = {"UseUnalignedAccesses", "true"}) static Object[] test1f(byte[] a) { UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 0, (byte)0xbe); UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 1, (byte)0xba); diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java new file mode 100644 index 00000000000..dbfdfe68957 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8335390 + * @summary Test merge stores for some Unsafe store address patterns. + * @modules java.base/jdk.internal.misc + * @requires vm.bits == 64 + * @requires os.maxMemory > 8G + * @run main/othervm -XX:CompileCommand=compileonly,compiler.c2.TestMergeStoresUnsafeArrayPointer::test* + * -Xbatch + * -Xmx8g + * compiler.c2.TestMergeStoresUnsafeArrayPointer + * @run main/othervm -Xmx8g + * compiler.c2.TestMergeStoresUnsafeArrayPointer + */ + +package compiler.c2; +import jdk.internal.misc.Unsafe; + +public class TestMergeStoresUnsafeArrayPointer { + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + // We allocate a big int array of length: + static final int SIZE = (1 << 30) + 100; + + // This gives us a memory region of 4x as many bytes: + static final long BYTE_SIZE = 4L * SIZE; // = 1L << 32 + 400L + + // We set an "anchor" in the middle of this memory region, in bytes: + static final long ANCHOR = BYTE_SIZE / 2; + + static int four = 4; + + public static void main(String[] args) { + System.out.println("Allocate big array of SIZE = " + SIZE); + int[] big = new int[SIZE]; + + // Each test is executed a few times, so that we can see the difference between + // interpreter and compiler. + int errors = 0; + + long val = 0; + System.out.println("test1"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test1(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test1 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test2"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test2(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test2 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + if (errors > 0) { + throw new RuntimeException("ERRORS: " + errors); + } + System.out.println("PASSED"); + } + + // Only clear and sum over relevant parts of array to make the test fast. + static void testClear(int[] a) { + for (int j = 0 ; j < 100; j++) { a[j] = j; } + for (int j = a.length/2 - 100; j < a.length/2 + 100; j++) { a[j] = j; } + for (int j = a.length - 100; j < a.length + 0; j++) { a[j] = j; } + } + + static long testSum(int[] a) { + long sum = 0; + for (int j = 0 ; j < 100; j++) { sum += a[j]; } + for (int j = a.length/2 - 100; j < a.length/2 + 100; j++) { sum += a[j]; } + for (int j = a.length - 100; j < a.length + 0; j++) { sum += a[j]; } + return sum; + } + + // Reference: expected to merge. + static void test1(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + 0, 0x42424242); + UNSAFE.putInt(a, base + 4, 0x66666666); + } + + // Test: if MergeStores is applied this can lead to wrong results + static void test2(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + ANCHOR; + UNSAFE.putInt(a, base + 0 + (long)(four + Integer.MAX_VALUE), 0x42424242); + UNSAFE.putInt(a, base + Integer.MAX_VALUE + (long)(four + 4 ), 0x66666666); + } +} From 4060b35b1d00fccbec4b20353063f77c43ecc686 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Jul 2024 08:58:20 +0000 Subject: [PATCH 48/85] 8335298: Fix -Wzero-as-null-pointer-constant warning in G1CardSetContainers Reviewed-by: iwalulya, ayang --- .../share/gc/g1/g1CardSetContainers.hpp | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 43e6c8a3bf7..84e6e3e9274 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,12 +86,22 @@ class G1CardSetInlinePtr : public StackObj { uint find(uint const card_idx, uint const bits_per_card, uint start_at, uint num_cards); + static ContainerPtr empty_card_set() { + // Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114573 + // gcc issues -Wzero-as-null-pointer-constant here, even though + // ContainerInlinePtr is a *non-literal* constant 0. We cast a non-const + // copy, and let the compiler's constant propagation optimize into + // equivalent code. + static_assert(G1CardSet::ContainerInlinePtr == 0, "unnecessary warning dodge"); + auto value = G1CardSet::ContainerInlinePtr; + return reinterpret_cast(value); + } + public: - G1CardSetInlinePtr() : _value_addr(nullptr), _value((ContainerPtr)G1CardSet::ContainerInlinePtr) { } + G1CardSetInlinePtr() : G1CardSetInlinePtr(empty_card_set()) {} - G1CardSetInlinePtr(ContainerPtr value) : _value_addr(nullptr), _value(value) { - assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); - } + explicit G1CardSetInlinePtr(ContainerPtr value) : + G1CardSetInlinePtr(nullptr, value) {} G1CardSetInlinePtr(ContainerPtr volatile* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); From a537e87d2d2c6bff63f63bb436e3e919740221ce Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 2 Jul 2024 11:50:21 +0000 Subject: [PATCH 49/85] 8335530: Java file extension missing in AuthenticatorTest Reviewed-by: cstein, jpai --- ...thenticatorTest => AuthenticatorTest.java} | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename test/jdk/com/sun/net/httpserver/{AuthenticatorTest => AuthenticatorTest.java} (75%) diff --git a/test/jdk/com/sun/net/httpserver/AuthenticatorTest b/test/jdk/com/sun/net/httpserver/AuthenticatorTest.java similarity index 75% rename from test/jdk/com/sun/net/httpserver/AuthenticatorTest rename to test/jdk/com/sun/net/httpserver/AuthenticatorTest.java index 1fe7f383035..1456af618fa 100644 --- a/test/jdk/com/sun/net/httpserver/AuthenticatorTest +++ b/test/jdk/com/sun/net/httpserver/AuthenticatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,36 +25,36 @@ * @test * @bug 8251496 * @summary Tests for methods in Authenticator - * @run testng/othervm AuthenticatorTest + * @run junit AuthenticatorTest */ import com.sun.net.httpserver.Authenticator; -import com.sun.net.httpserver.BasicAuthenticator; import com.sun.net.httpserver.HttpPrincipal; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class AuthenticatorTest { @Test public void testFailure() { var failureResult = new Authenticator.Failure(666); - assertEquals(failureResult.getResponseCode(), 666); + assertEquals(666, failureResult.getResponseCode()); } @Test public void testRetry() { var retryResult = new Authenticator.Retry(333); - assertEquals(retryResult.getResponseCode(), 333); + assertEquals(333, retryResult.getResponseCode()); } @Test - public void TestSuccess() { + public void testSuccess() { var principal = new HttpPrincipal("test", "123"); var successResult = new Authenticator.Success(principal); - assertEquals(successResult.getPrincipal(), principal); - assertEquals("test", principal.getName()); + assertEquals(principal, successResult.getPrincipal()); + assertEquals("test", principal.getUsername()); assertEquals("123", principal.getRealm()); } } From dd74e7f8c1570ed34c89f4aca184f5668e4471db Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Jul 2024 12:15:02 +0000 Subject: [PATCH 50/85] 8335147: Serial: Refactor TenuredGeneration::promote Reviewed-by: tschatzl, iwalulya --- .../share/gc/serial/defNewGeneration.cpp | 20 +++++++++---------- .../share/gc/serial/tenuredGeneration.cpp | 10 ++-------- .../share/gc/serial/tenuredGeneration.hpp | 5 ++--- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index b66681170c6..593977030cb 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -768,25 +768,25 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { bool new_obj_is_tenured = false; // Otherwise try allocating obj tenured if (obj == nullptr) { - obj = _old_gen->promote(old, s); + obj = _old_gen->allocate_for_promotion(old, s); if (obj == nullptr) { handle_promotion_failure(old); return old; } - ContinuationGCSupport::transform_stack_chunk(obj); - new_obj_is_tenured = true; - } else { - // Prefetch beyond obj - const intx interval = PrefetchCopyIntervalInBytes; - Prefetch::write(obj, interval); + } + + // Prefetch beyond obj + const intx interval = PrefetchCopyIntervalInBytes; + Prefetch::write(obj, interval); - // Copy obj - Copy::aligned_disjoint_words(cast_from_oop(old), cast_from_oop(obj), s); + // Copy obj + Copy::aligned_disjoint_words(cast_from_oop(old), cast_from_oop(obj), s); - ContinuationGCSupport::transform_stack_chunk(obj); + ContinuationGCSupport::transform_stack_chunk(obj); + if (!new_obj_is_tenured) { // Increment age if obj still in new generation obj->incr_age(); age_table()->add(obj, s); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index 1cddce2dc51..f1389b48557 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -387,7 +387,7 @@ bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) return res; } -oop TenuredGeneration::promote(oop obj, size_t obj_size) { +oop TenuredGeneration::allocate_for_promotion(oop obj, size_t obj_size) { assert(obj_size == obj->size(), "bad obj_size passed in"); #ifndef PRODUCT @@ -401,15 +401,9 @@ oop TenuredGeneration::promote(oop obj, size_t obj_size) { if (result == nullptr) { // Promotion of obj into gen failed. Try to expand and allocate. result = expand_and_allocate(obj_size, false); - if (result == nullptr) { - return nullptr; - } } - // Copy to new location. - Copy::aligned_disjoint_words(cast_from_oop(obj), result, obj_size); - oop new_obj = cast_to_oop(result); - return new_obj; + return cast_to_oop(result); } HeapWord* diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index dc2730eaf41..bcb2d668213 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -163,12 +163,11 @@ class TenuredGeneration: public Generation { bool promotion_attempt_is_safe(size_t max_promoted_in_bytes) const; // "obj" is the address of an object in young-gen. Allocate space for "obj" - // in the old-gen, and copy "obj" into the newly allocated space, if - // possible, returning the result (or null if the allocation failed). + // in the old-gen, returning the result (or null if the allocation failed). // // The "obj_size" argument is just obj->size(), passed along so the caller can // avoid repeating the virtual call to retrieve it. - oop promote(oop obj, size_t obj_size); + oop allocate_for_promotion(oop obj, size_t obj_size); virtual void verify(); virtual void print_on(outputStream* st) const; From 685e5878b823fa5e3ae88ffd76de6507d6057af2 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Tue, 2 Jul 2024 14:36:29 +0000 Subject: [PATCH 51/85] 8334816: compiler/c2/irTests/TestIfMinMax.java fails after 8334629 Reviewed-by: thartmann, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 1 - .../compiler/c2/irTests/TestIfMinMax.java | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 0f574f7168a..2d1311e3ac1 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -53,7 +53,6 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all -compiler/c2/irTests/TestIfMinMax.java 8334816 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/CheckLargePages.java 8332654 linux-x64 diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index de0b41e73ea..41402036aea 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -181,19 +181,19 @@ static Object[] setupIntArrays() { int[] a = new int[512]; int[] b = new int[512]; - // Fill from 1 to 50 - for (int i = 0; i < 50; i++) { + // Fill from 1 to 125 + for (int i = 0; i < 125; i++) { a[i] = i + 1; b[i] = 1; } - // Fill from -1 to -50 - for (int i = 50; i < 100; i++) { - a[i] = -(i - 49); + // Fill from -1 to -125 + for (int i = 125; i < 250; i++) { + a[i] = -(i - 124); b[i] = 1; } - for (int i = 100; i < 512; i++) { + for (int i = 250; i < 512; i++) { a[i] = RANDOM.nextInt(); b[i] = 1; } @@ -206,19 +206,19 @@ static Object[] setupLongArrays() { long[] a = new long[512]; long[] b = new long[512]; - // Fill from 1 to 50 - for (int i = 0; i < 50; i++) { + // Fill from 1 to 125 + for (int i = 0; i < 125; i++) { a[i] = i + 1; b[i] = 1; } - // Fill from -1 to -50 - for (int i = 50; i < 100; i++) { - a[i] = -(i - 49); + // Fill from -1 to -125 + for (int i = 125; i < 250; i++) { + a[i] = -(i - 124); b[i] = 1; } - for (int i = 100; i < 512; i++) { + for (int i = 250; i < 512; i++) { a[i] = RANDOM.nextLong(); b[i] = 1; } From 153b12b9df87fdf8122cae3bf7f13078f55f7101 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 2 Jul 2024 15:38:54 +0000 Subject: [PATCH 52/85] 8331560: Refactor Hotspot container detection code so that subsystem delegates to controllers Reviewed-by: jsjolen, stuefe --- .../os/linux/cgroupSubsystem_linux.cpp | 123 ++++++++------- .../os/linux/cgroupSubsystem_linux.hpp | 59 +++++--- src/hotspot/os/linux/cgroupUtil_linux.cpp | 48 ++++++ src/hotspot/os/linux/cgroupUtil_linux.hpp | 37 +++++ .../os/linux/cgroupV1Subsystem_linux.cpp | 141 ++++++++++-------- .../os/linux/cgroupV1Subsystem_linux.hpp | 120 +++++++++------ .../os/linux/cgroupV2Subsystem_linux.cpp | 133 ++++++++++------- .../os/linux/cgroupV2Subsystem_linux.hpp | 114 +++++++++----- 8 files changed, 511 insertions(+), 264 deletions(-) create mode 100644 src/hotspot/os/linux/cgroupUtil_linux.cpp create mode 100644 src/hotspot/os/linux/cgroupUtil_linux.hpp diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 0dbd6ffd52b..1da0e44dbf4 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -28,6 +28,7 @@ #include "cgroupSubsystem_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "os_linux.hpp" @@ -41,7 +42,7 @@ static const char* cg_controller_name[] = { "cpu", "cpuset", "cpuacct", "memory" CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupV1MemoryController* memory = nullptr; CgroupV1Controller* cpuset = nullptr; - CgroupV1Controller* cpu = nullptr; + CgroupV1CpuController* cpu = nullptr; CgroupV1Controller* cpuacct = nullptr; CgroupV1Controller* pids = nullptr; CgroupInfo cg_infos[CG_INFO_LENGTH]; @@ -61,14 +62,18 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { if (is_cgroup_v2(&cg_type_flags)) { // Cgroups v2 case, we have all the info we need. // Construct the subsystem, free resources and return - // Note: any index in cg_infos will do as the path is the same for - // all controllers. - CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, - cg_infos[MEMORY_IDX]._cgroup_path, - cg_infos[MEMORY_IDX]._read_only); + // Note: We use the memory for non-cpu non-memory controller look-ups. + // Perhaps we ought to have separate controllers for all. + CgroupV2Controller mem_other = CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, + cg_infos[MEMORY_IDX]._cgroup_path, + cg_infos[MEMORY_IDX]._read_only); + CgroupV2MemoryController* memory = new CgroupV2MemoryController(mem_other); + CgroupV2CpuController* cpu = new CgroupV2CpuController(CgroupV2Controller(cg_infos[CPU_IDX]._mount_path, + cg_infos[CPU_IDX]._cgroup_path, + cg_infos[CPU_IDX]._read_only)); log_debug(os, container)("Detected cgroups v2 unified hierarchy"); cleanup(cg_infos); - return new CgroupV2Subsystem(unified); + return new CgroupV2Subsystem(memory, cpu, mem_other); } /* @@ -102,13 +107,13 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupInfo info = cg_infos[i]; if (info._data_complete) { // pids controller might have incomplete data if (strcmp(info._name, "memory") == 0) { - memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path, info._read_only); + memory = new CgroupV1MemoryController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); memory->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuset") == 0) { cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuset->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpu") == 0) { - cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); + cpu = new CgroupV1CpuController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); cpu->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuacct") == 0) { cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); @@ -556,13 +561,13 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { */ int CgroupSubsystem::active_processor_count() { int quota_count = 0; - int cpu_count, limit_count; + int cpu_count; int result; // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. - CachingCgroupController* contrl = cpu_controller(); + CachingCgroupController* contrl = cpu_controller(); CachedMetric* cpu_limit = contrl->metrics_cache(); if (!cpu_limit->should_check_metric()) { int val = (int)cpu_limit->value(); @@ -570,23 +575,8 @@ int CgroupSubsystem::active_processor_count() { return val; } - cpu_count = limit_count = os::Linux::active_processor_count(); - int quota = cpu_quota(); - int period = cpu_period(); - - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); - } - - // Use quotas - if (quota_count != 0) { - limit_count = quota_count; - } - - result = MIN2(cpu_count, limit_count); - log_trace(os, container)("OSContainer::active_processor_count: %d", result); - + cpu_count = os::Linux::active_processor_count(); + result = CgroupUtil::processor_count(contrl->controller(), cpu_count); // Update cached metric to avoid re-reading container settings too often cpu_limit->set_value(result, OSCONTAINER_CACHE_TIMEOUT); @@ -603,35 +593,14 @@ int CgroupSubsystem::active_processor_count() { * OSCONTAINER_ERROR for not supported */ jlong CgroupSubsystem::memory_limit_in_bytes() { - CachingCgroupController* contrl = memory_controller(); + CachingCgroupController* contrl = memory_controller(); CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { return memory_limit->value(); } jlong phys_mem = os::Linux::physical_memory(); log_trace(os, container)("total physical memory: " JLONG_FORMAT, phys_mem); - jlong mem_limit = read_memory_limit_in_bytes(); - - if (mem_limit <= 0 || mem_limit >= phys_mem) { - jlong read_mem_limit = mem_limit; - const char *reason; - if (mem_limit >= phys_mem) { - // Exceeding physical memory is treated as unlimited. Cg v1's implementation - // of read_memory_limit_in_bytes() caps this at phys_mem since Cg v1 has no - // value to represent 'max'. Cg v2 may return a value >= phys_mem if e.g. the - // container engine was started with a memory flag exceeding it. - reason = "ignored"; - mem_limit = -1; - } else if (OSCONTAINER_ERROR == mem_limit) { - reason = "failed"; - } else { - assert(mem_limit == -1, "Expected unlimited"); - reason = "unlimited"; - } - log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, - reason, read_mem_limit, phys_mem); - } - + jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem); // Update cached metric to avoid re-reading container settings too often memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); return mem_limit; @@ -796,3 +765,55 @@ jlong CgroupController::limit_from_str(char* limit_str) { } return (jlong)limit; } + +// CgroupSubsystem implementations + +jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + julong host_swap = os::Linux::host_swap(); + return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap); +} + +jlong CgroupSubsystem::memory_and_swap_usage_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + julong host_swap = os::Linux::host_swap(); + return memory_controller()->controller()->memory_and_swap_usage_in_bytes(phys_mem, host_swap); +} + +jlong CgroupSubsystem::memory_soft_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); +} + +jlong CgroupSubsystem::memory_usage_in_bytes() { + return memory_controller()->controller()->memory_usage_in_bytes(); +} + +jlong CgroupSubsystem::memory_max_usage_in_bytes() { + return memory_controller()->controller()->memory_max_usage_in_bytes(); +} + +jlong CgroupSubsystem::rss_usage_in_bytes() { + return memory_controller()->controller()->rss_usage_in_bytes(); +} + +jlong CgroupSubsystem::cache_usage_in_bytes() { + return memory_controller()->controller()->cache_usage_in_bytes(); +} + +int CgroupSubsystem::cpu_quota() { + return cpu_controller()->controller()->cpu_quota(); +} + +int CgroupSubsystem::cpu_period() { + return cpu_controller()->controller()->cpu_period(); +} + +int CgroupSubsystem::cpu_shares() { + return cpu_controller()->controller()->cpu_shares(); +} + +void CgroupSubsystem::print_version_specific_info(outputStream* st) { + julong phys_mem = os::Linux::physical_memory(); + memory_controller()->controller()->print_version_specific_info(st, phys_mem); +} diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 00419c77570..4d5fa5d4879 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -180,48 +180,73 @@ class CachedMetric : public CHeapObj{ } }; +template class CachingCgroupController : public CHeapObj { private: - CgroupController* _controller; + T* _controller; CachedMetric* _metrics_cache; public: - CachingCgroupController(CgroupController* cont) { + CachingCgroupController(T* cont) { _controller = cont; _metrics_cache = new CachedMetric(); } CachedMetric* metrics_cache() { return _metrics_cache; } - CgroupController* controller() { return _controller; } + T* controller() { return _controller; } }; -class CgroupSubsystem: public CHeapObj { +// Pure virtual class representing version agnostic CPU controllers +class CgroupCpuController: public CHeapObj { public: - jlong memory_limit_in_bytes(); - int active_processor_count(); - virtual int cpu_quota() = 0; virtual int cpu_period() = 0; virtual int cpu_shares() = 0; - virtual jlong pids_max() = 0; - virtual jlong pids_current() = 0; + virtual bool is_read_only() = 0; +}; + +// Pure virtual class representing version agnostic memory controllers +class CgroupMemoryController: public CHeapObj { + public: + virtual jlong read_memory_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_usage_in_bytes() = 0; - virtual jlong memory_and_swap_limit_in_bytes() = 0; - virtual jlong memory_and_swap_usage_in_bytes() = 0; - virtual jlong memory_soft_limit_in_bytes() = 0; + virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_max_usage_in_bytes() = 0; virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; + virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; + virtual bool is_read_only() = 0; +}; + +class CgroupSubsystem: public CHeapObj { + public: + jlong memory_limit_in_bytes(); + int active_processor_count(); + + virtual jlong pids_max() = 0; + virtual jlong pids_current() = 0; virtual bool is_containerized() = 0; virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; - virtual jlong read_memory_limit_in_bytes() = 0; virtual const char * container_type() = 0; - virtual CachingCgroupController* memory_controller() = 0; - virtual CachingCgroupController* cpu_controller() = 0; - - virtual void print_version_specific_info(outputStream* st) = 0; + virtual CachingCgroupController* memory_controller() = 0; + virtual CachingCgroupController* cpu_controller() = 0; + + int cpu_quota(); + int cpu_period(); + int cpu_shares(); + + jlong memory_usage_in_bytes(); + jlong memory_and_swap_limit_in_bytes(); + jlong memory_and_swap_usage_in_bytes(); + jlong memory_soft_limit_in_bytes(); + jlong memory_max_usage_in_bytes(); + jlong rss_usage_in_bytes(); + jlong cache_usage_in_bytes(); + void print_version_specific_info(outputStream* st); }; // Utility class for storing info retrieved from /proc/cgroups, diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp new file mode 100644 index 00000000000..24046991905 --- /dev/null +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cgroupUtil_linux.hpp" + +int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { + assert(host_cpus > 0, "physical host cpus must be positive"); + int limit_count = host_cpus; + int quota = cpu_ctrl->cpu_quota(); + int period = cpu_ctrl->cpu_period(); + int quota_count = 0; + int result = 0; + + if (quota > -1 && period > 0) { + quota_count = ceilf((float)quota / (float)period); + log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + } + + // Use quotas + if (quota_count != 0) { + limit_count = quota_count; + } + + result = MIN2(host_cpus, limit_count); + log_trace(os, container)("OSContainer::active_processor_count: %d", result); + return result; +} diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp new file mode 100644 index 00000000000..fdcc4806c3b --- /dev/null +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CGROUP_UTIL_LINUX_HPP +#define CGROUP_UTIL_LINUX_HPP + +#include "utilities/globalDefinitions.hpp" +#include "cgroupSubsystem_linux.hpp" + +class CgroupUtil: AllStatic { + + public: + static int processor_count(CgroupCpuController* cpu, int host_cpus); +}; + +#endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 3f6ae813810..d7f9918afda 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -26,6 +26,7 @@ #include #include #include "cgroupV1Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "runtime/globals.hpp" @@ -76,42 +77,62 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { */ jlong CgroupV1MemoryController::uses_mem_hierarchy() { julong use_hierarchy; - CONTAINER_READ_NUMBER_CHECKED(this, "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); return (jlong)use_hierarchy; } void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { - CgroupV1Controller::set_subsystem_path(cgroup_path); + reader()->set_subsystem_path(cgroup_path); jlong hierarchy = uses_mem_hierarchy(); if (hierarchy > 0) { set_hierarchical(true); } } -jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { +static inline +void verbose_log(julong read_mem_limit, julong host_mem) { + if (log_is_enabled(Debug, os, container)) { + jlong mem_limit = (jlong)read_mem_limit; // account for negative values + if (mem_limit < 0 || read_mem_limit >= host_mem) { + const char *reason; + if (mem_limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else if (mem_limit == -1) { + reason = "unlimited"; + } else { + assert(read_mem_limit >= host_mem, "Expected read value exceeding host_mem"); + // Exceeding physical memory is treated as unlimited. This implementation + // caps it at host_mem since Cg v1 has no value to represent 'max'. + reason = "ignored"; + } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, mem_limit, host_mem); + } + } +} + +jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { julong memlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.limit_in_bytes", "Memory Limit", memlimit); - if (memlimit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit); + if (memlimit >= phys_mem) { log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { + if (is_hierarchical()) { julong hier_memlimit; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "hierarchical_memory_limit", - &hier_memlimit); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "hierarchical_memory_limit", &hier_memlimit); if (!is_ok) { return OSCONTAINER_ERROR; } log_trace(os, container)("Hierarchical Memory Limit is: " JULONG_FORMAT, hier_memlimit); - if (hier_memlimit >= os::Linux::physical_memory()) { - log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); - } else { + if (hier_memlimit < phys_mem) { + verbose_log(hier_memlimit, phys_mem); return (jlong)hier_memlimit; } + log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); } + verbose_log(memlimit, phys_mem); return (jlong)-1; - } - else { + } else { + verbose_log(memlimit, phys_mem); return (jlong)memlimit; } } @@ -128,20 +149,17 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { * * -1 if there isn't any limit in place (note: includes values which exceed a physical * upper bound) */ -jlong CgroupV1Subsystem::read_mem_swap() { - julong host_total_memsw; +jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { julong hier_memswlimit; julong memswlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); - host_total_memsw = os::Linux::host_swap() + os::Linux::physical_memory(); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); if (memswlimit >= host_total_memsw) { log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { + if (is_hierarchical()) { const char* matchline = "hierarchical_memsw_limit"; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - matchline, - &hier_memswlimit); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", + matchline, + &hier_memswlimit); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -158,8 +176,8 @@ jlong CgroupV1Subsystem::read_mem_swap() { } } -jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { - jlong memory_swap = read_mem_swap(); +jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) { + jlong memory_swap = read_mem_swap(host_mem + host_swap); if (memory_swap == -1) { return memory_swap; } @@ -168,7 +186,7 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { // supported. jlong swappiness = read_mem_swappiness(); if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) { - jlong memlimit = read_memory_limit_in_bytes(); + jlong memlimit = read_memory_limit_in_bytes(host_mem); if (memory_swap == OSCONTAINER_ERROR) { log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit); } else { @@ -186,28 +204,28 @@ jlong memory_swap_usage_impl(CgroupController* ctrl) { return (jlong)memory_swap_usage; } -jlong CgroupV1Subsystem::memory_and_swap_usage_in_bytes() { - jlong memory_sw_limit = memory_and_swap_limit_in_bytes(); - jlong memory_limit = CgroupSubsystem::memory_limit_in_bytes(); +jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong phys_mem, julong host_swap) { + jlong memory_sw_limit = memory_and_swap_limit_in_bytes(phys_mem, host_swap); + jlong memory_limit = read_memory_limit_in_bytes(phys_mem); if (memory_sw_limit > 0 && memory_limit > 0) { jlong delta_swap = memory_sw_limit - memory_limit; if (delta_swap > 0) { - return memory_swap_usage_impl(_memory->controller()); + return memory_swap_usage_impl(reader()); } } return memory_usage_in_bytes(); } -jlong CgroupV1Subsystem::read_mem_swappiness() { +jlong CgroupV1MemoryController::read_mem_swappiness() { julong swappiness; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.swappiness", "Swappiness", swappiness); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.swappiness", "Swappiness", swappiness); return (jlong)swappiness; } -jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { +jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { julong memsoftlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); - if (memsoftlimit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); + if (memsoftlimit >= phys_mem) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; } else { @@ -235,9 +253,9 @@ bool CgroupV1Subsystem::is_containerized() { * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_usage_in_bytes() { +jlong CgroupV1MemoryController::memory_usage_in_bytes() { julong memusage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.usage_in_bytes", "Memory Usage", memusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.usage_in_bytes", "Memory Usage", memusage); return (jlong)memusage; } @@ -249,17 +267,15 @@ jlong CgroupV1Subsystem::memory_usage_in_bytes() { * max memory usage in bytes or * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { +jlong CgroupV1MemoryController::memory_max_usage_in_bytes() { julong memmaxusage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); return (jlong)memmaxusage; } -jlong CgroupV1Subsystem::rss_usage_in_bytes() { +jlong CgroupV1MemoryController::rss_usage_in_bytes() { julong rss; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "rss", - &rss); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "rss", &rss); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -267,11 +283,9 @@ jlong CgroupV1Subsystem::rss_usage_in_bytes() { return (jlong)rss; } -jlong CgroupV1Subsystem::cache_usage_in_bytes() { +jlong CgroupV1MemoryController::cache_usage_in_bytes() { julong cache; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "cache", - &cache); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "cache", &cache); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -279,30 +293,30 @@ jlong CgroupV1Subsystem::cache_usage_in_bytes() { return cache; } -jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_usage_in_bytes() { julong kmem_usage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); return (jlong)kmem_usage; } -jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong phys_mem) { julong kmem_limit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); - if (kmem_limit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); + if (kmem_limit >= phys_mem) { return (jlong)-1; } return (jlong)kmem_limit; } -jlong CgroupV1Subsystem::kernel_memory_max_usage_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_max_usage_in_bytes() { julong kmem_max_usage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); return (jlong)kmem_max_usage; } -void CgroupV1Subsystem::print_version_specific_info(outputStream* st) { +void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { jlong kmem_usage = kernel_memory_usage_in_bytes(); - jlong kmem_limit = kernel_memory_limit_in_bytes(); + jlong kmem_limit = kernel_memory_limit_in_bytes(phys_mem); jlong kmem_max_usage = kernel_memory_max_usage_in_bytes(); OSContainer::print_container_helper(st, kmem_usage, "kernel_memory_usage_in_bytes"); @@ -332,10 +346,9 @@ char* CgroupV1Subsystem::cpu_cpuset_memory_nodes() { * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_quota() { +int CgroupV1CpuController::cpu_quota() { julong quota; - bool is_ok = _cpu->controller()-> - read_number("/cpu.cfs_quota_us", "a); + bool is_ok = reader()->read_number("/cpu.cfs_quota_us", "a); if (!is_ok) { log_trace(os, container)("CPU Quota failed: %d", OSCONTAINER_ERROR); return OSCONTAINER_ERROR; @@ -347,9 +360,9 @@ int CgroupV1Subsystem::cpu_quota() { return quota_int; } -int CgroupV1Subsystem::cpu_period() { +int CgroupV1CpuController::cpu_period() { julong period; - CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.cfs_period_us", "CPU Period", period); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.cfs_period_us", "CPU Period", period); return (int)period; } @@ -363,9 +376,9 @@ int CgroupV1Subsystem::cpu_period() { * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_shares() { +int CgroupV1CpuController::cpu_shares() { julong shares; - CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.shares", "CPU Shares", shares); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.shares", "CPU Shares", shares); int shares_int = (int)shares; // Convert 1024 to no shares setup if (shares_int == 1024) return -1; diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 2b67678c2e8..251fbde85f0 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -34,31 +34,60 @@ class CgroupV1Controller: public CgroupController { private: /* mountinfo contents */ - char *_root; - char *_mount_point; + char* _root; + char* _mount_point; bool _read_only; /* Constructed subsystem directory */ - char *_path; + char* _path; public: - CgroupV1Controller(char *root, char *mountpoint, bool ro) { - _root = os::strdup(root); - _mount_point = os::strdup(mountpoint); - _path = nullptr; - _read_only = ro; + CgroupV1Controller(char *root, + char *mountpoint, + bool ro) : _root(os::strdup(root)), + _mount_point(os::strdup(mountpoint)), + _read_only(ro), + _path(nullptr) { + } + // Shallow copy constructor + CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root), + _mount_point(o._mount_point), + _read_only(o._read_only), + _path(o._path) { + } + ~CgroupV1Controller() { + // At least one subsystem controller exists with paths to malloc'd path + // names } - virtual void set_subsystem_path(char *cgroup_path); - char *subsystem_path() { return _path; } + void set_subsystem_path(char *cgroup_path); + char *subsystem_path() override { return _path; } bool is_read_only() { return _read_only; } }; -class CgroupV1MemoryController: public CgroupV1Controller { +class CgroupV1MemoryController final : public CgroupMemoryController { + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } public: bool is_hierarchical() { return _uses_mem_hierarchy; } void set_subsystem_path(char *cgroup_path); + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + jlong kernel_memory_usage_in_bytes(); + jlong kernel_memory_limit_in_bytes(julong host_mem); + jlong kernel_memory_max_usage_in_bytes(); + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool is_read_only() override { + return reader()->is_read_only(); + } private: /* Some container runtimes set limits via cgroup * hierarchy. If set to true consider also memory.stat @@ -66,26 +95,41 @@ class CgroupV1MemoryController: public CgroupV1Controller { bool _uses_mem_hierarchy; jlong uses_mem_hierarchy(); void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } + jlong read_mem_swappiness(); + jlong read_mem_swap(julong host_total_memsw); public: - CgroupV1MemoryController(char *root, char *mountpoint, bool ro) : CgroupV1Controller(root, mountpoint, ro) { - _uses_mem_hierarchy = false; + CgroupV1MemoryController(const CgroupV1Controller& reader) + : _reader(reader), + _uses_mem_hierarchy(false) { } }; -class CgroupV1Subsystem: public CgroupSubsystem { +class CgroupV1CpuController final : public CgroupCpuController { + + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } + public: + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + void set_subsystem_path(char *cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + bool is_read_only() override { + return reader()->is_read_only(); + } public: - jlong read_memory_limit_in_bytes(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_and_swap_usage_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); - jlong rss_usage_in_bytes(); - jlong cache_usage_in_bytes(); + CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) { + } +}; + +class CgroupV1Subsystem: public CgroupSubsystem { + public: jlong kernel_memory_usage_in_bytes(); jlong kernel_memory_limit_in_bytes(); jlong kernel_memory_max_usage_in_bytes(); @@ -93,45 +137,35 @@ class CgroupV1Subsystem: public CgroupSubsystem { char * cpu_cpuset_cpus(); char * cpu_cpuset_memory_nodes(); - int cpu_quota(); - int cpu_period(); - - int cpu_shares(); - jlong pids_max(); jlong pids_current(); bool is_containerized(); - void print_version_specific_info(outputStream* st); - const char * container_type() { return "cgroupv1"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() { return _memory; } + CachingCgroupController* cpu_controller() { return _cpu; } private: /* controllers */ - CachingCgroupController* _memory = nullptr; + CachingCgroupController* _memory = nullptr; CgroupV1Controller* _cpuset = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupV1Controller* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; - jlong read_mem_swappiness(); - jlong read_mem_swap(); - public: CgroupV1Subsystem(CgroupV1Controller* cpuset, - CgroupV1Controller* cpu, + CgroupV1CpuController* cpu, CgroupV1Controller* cpuacct, CgroupV1Controller* pids, - CgroupV1MemoryController* memory) { - _cpuset = cpuset; - _cpu = new CachingCgroupController(cpu); - _cpuacct = cpuacct; - _pids = pids; - _memory = new CachingCgroupController(memory); + CgroupV1MemoryController* memory) : + _memory(new CachingCgroupController(memory)), + _cpuset(cpuset), + _cpu(new CachingCgroupController(cpu)), + _cpuacct(cpuacct), + _pids(pids) { } }; diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 1f97b021239..8f7e12d0954 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -23,6 +23,7 @@ */ #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" /* cpu_shares * @@ -34,9 +35,9 @@ * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_shares() { +int CgroupV2CpuController::cpu_shares() { julong shares; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/cpu.weight", "Raw value for CPU Shares", shares); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.weight", "Raw value for CPU Shares", shares); int shares_int = (int)shares; // Convert default value of 100 to no shares setup if (shares_int == 100) { @@ -83,9 +84,9 @@ int CgroupV2Subsystem::cpu_shares() { * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_quota() { +int CgroupV2CpuController::cpu_quota() { jlong quota_val; - bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -95,24 +96,26 @@ int CgroupV2Subsystem::cpu_quota() { } bool CgroupV2Subsystem::is_containerized() { - return _unified->is_read_only(); + return _unified.is_read_only() && + _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only(); } char* CgroupV2Subsystem::cpu_cpuset_cpus() { char cpus[1024]; - CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } char* CgroupV2Subsystem::cpu_cpuset_memory_nodes() { char mems[1024]; - CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.mems", "cpuset.mems", mems, 1024); + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } -int CgroupV2Subsystem::cpu_period() { +int CgroupV2CpuController::cpu_period() { jlong period_val; - bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); if (!is_ok) { log_trace(os, container)("CPU Period failed: %d", OSCONTAINER_ERROR); return OSCONTAINER_ERROR; @@ -131,28 +134,27 @@ int CgroupV2Subsystem::cpu_period() { * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV2Subsystem::memory_usage_in_bytes() { +jlong CgroupV2MemoryController::memory_usage_in_bytes() { julong memusage; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.current", "Memory Usage", memusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.current", "Memory Usage", memusage); return (jlong)memusage; } -jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() { +jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { jlong mem_soft_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.low", "Memory Soft Limit", mem_soft_limit); + CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.low", "Memory Soft Limit", mem_soft_limit); return mem_soft_limit; } -jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { +jlong CgroupV2MemoryController::memory_max_usage_in_bytes() { // Log this string at trace level so as to make tests happy. log_trace(os, container)("Maximum Memory Usage is not supported."); return OSCONTAINER_ERROR; // not supported } -jlong CgroupV2Subsystem::rss_usage_in_bytes() { +jlong CgroupV2MemoryController::rss_usage_in_bytes() { julong rss; - bool is_ok = _memory->controller()-> - read_numerical_key_value("/memory.stat", "anon", &rss); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "anon", &rss); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -160,10 +162,9 @@ jlong CgroupV2Subsystem::rss_usage_in_bytes() { return (jlong)rss; } -jlong CgroupV2Subsystem::cache_usage_in_bytes() { +jlong CgroupV2MemoryController::cache_usage_in_bytes() { julong cache; - bool is_ok = _memory->controller()-> - read_numerical_key_value("/memory.stat", "file", &cache); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "file", &cache); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -176,18 +177,19 @@ jlong CgroupV2Subsystem::cache_usage_in_bytes() { // respectively. In order to properly report a cgroup v1 like // compound value we need to sum the two values. Setting a swap limit // without also setting a memory limit is not allowed. -jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { +jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong phys_mem, + julong host_swap /* unused in cg v2 */) { jlong swap_limit; - bool is_ok = _memory->controller()->read_number_handle_max("/memory.swap.max", &swap_limit); + bool is_ok = reader()->read_number_handle_max("/memory.swap.max", &swap_limit); if (!is_ok) { // Some container tests rely on this trace logging to happen. log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR); // swap disabled at kernel level, treat it as no swap - return read_memory_limit_in_bytes(); + return read_memory_limit_in_bytes(phys_mem); } log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit); if (swap_limit >= 0) { - jlong memory_limit = read_memory_limit_in_bytes(); + jlong memory_limit = read_memory_limit_in_bytes(phys_mem); assert(memory_limit >= 0, "swap limit without memory limit?"); return memory_limit + swap_limit; } @@ -195,29 +197,31 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { return swap_limit; } -jlong CgroupV2Subsystem::memory_and_swap_usage_in_bytes() { - jlong memory_usage = memory_usage_in_bytes(); - if (memory_usage >= 0) { - jlong swap_current = mem_swp_current_val(); - return memory_usage + (swap_current >= 0 ? swap_current : 0); - } - return memory_usage; // not supported or unlimited case +// memory.swap.current : total amount of swap currently used by the cgroup and its descendants +static +jlong memory_swap_current_value(CgroupV2Controller* ctrl) { + julong swap_current; + CONTAINER_READ_NUMBER_CHECKED(ctrl, "/memory.swap.current", "Swap currently used", swap_current); + return (jlong)swap_current; } -jlong CgroupV2Subsystem::mem_swp_limit_val() { - jlong swap_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.swap.max", "Swap Limit", swap_limit); - return swap_limit; +jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) { + jlong memory_usage = memory_usage_in_bytes(); + if (memory_usage >= 0) { + jlong swap_current = memory_swap_current_value(reader()); + return memory_usage + (swap_current >= 0 ? swap_current : 0); + } + return memory_usage; // not supported or unlimited case } -// memory.swap.current : total amount of swap currently used by the cgroup and its descendants -jlong CgroupV2Subsystem::mem_swp_current_val() { - julong swap_current; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.swap.current", "Swap currently used", swap_current); - return (jlong)swap_current; +static +jlong memory_limit_value(CgroupV2Controller* ctrl) { + jlong memory_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.max", "Memory Limit", memory_limit); + return memory_limit; } -/* memory_limit_in_bytes +/* read_memory_limit_in_bytes * * Return the limit of available memory for this process. * @@ -225,15 +229,44 @@ jlong CgroupV2Subsystem::mem_swp_current_val() { * memory limit in bytes or * -1 for unlimited, OSCONTAINER_ERROR for an error */ -jlong CgroupV2Subsystem::read_memory_limit_in_bytes() { - jlong memory_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.max", "Memory Limit", memory_limit); - return memory_limit; +jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) { + jlong limit = memory_limit_value(reader()); + if (log_is_enabled(Trace, os, container)) { + if (limit == -1) { + log_trace(os, container)("Memory Limit is: Unlimited"); + } else { + log_trace(os, container)("Memory Limit is: " JLONG_FORMAT, limit); + } + } + if (log_is_enabled(Debug, os, container)) { + julong read_limit = (julong)limit; // avoid signed/unsigned compare + if (limit < 0 || read_limit >= phys_mem) { + const char* reason; + if (limit == -1) { + reason = "unlimited"; + } else if (limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else { + assert(read_limit >= phys_mem, "Expected mem limit to exceed host memory"); + reason = "ignored"; + } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, limit, phys_mem); + } + } + return limit; +} + +static +jlong memory_swap_limit_value(CgroupV2Controller* ctrl) { + jlong swap_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.swap.max", "Swap Limit", swap_limit); + return swap_limit; } -void CgroupV2Subsystem::print_version_specific_info(outputStream* st) { - jlong swap_current = mem_swp_current_val(); - jlong swap_limit = mem_swp_limit_val(); +void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { + jlong swap_current = memory_swap_current_value(reader()); + jlong swap_limit = memory_swap_limit_value(reader()); OSContainer::print_container_helper(st, swap_current, "memory_swap_current_in_bytes"); OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); @@ -259,7 +292,7 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { */ jlong CgroupV2Subsystem::pids_max() { jlong pids_max; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/pids.max", "Maximum number of tasks", pids_max); + CONTAINER_READ_NUMBER_CHECKED_MAX(unified(), "/pids.max", "Maximum number of tasks", pids_max); return pids_max; } @@ -273,6 +306,6 @@ jlong CgroupV2Subsystem::pids_max() { */ jlong CgroupV2Subsystem::pids_current() { julong pids_current; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/pids.current", "Current number of tasks", pids_current); + CONTAINER_READ_NUMBER_CHECKED(unified(), "/pids.current", "Current number of tasks", pids_current); return pids_current; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 8e06466a138..02774fb70ae 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -40,60 +40,96 @@ class CgroupV2Controller: public CgroupController { static char* construct_path(char* mount_path, char *cgroup_path); public: - CgroupV2Controller(char * mount_path, char *cgroup_path, bool ro) { - _mount_path = mount_path; - _cgroup_path = os::strdup(cgroup_path); - _path = construct_path(mount_path, cgroup_path); - _read_only = ro; + CgroupV2Controller(char* mount_path, + char *cgroup_path, + bool ro) : _mount_path(os::strdup(mount_path)), + _cgroup_path(os::strdup(cgroup_path)), + _read_only(ro), + _path(construct_path(mount_path, cgroup_path)) { + } + // Shallow copy constructor + CgroupV2Controller(const CgroupV2Controller& o) : + _mount_path(o._mount_path), + _cgroup_path(o._cgroup_path), + _read_only(o._read_only), + _path(o._path) { + } + ~CgroupV2Controller() { + // At least one controller exists with references to the paths } - char *subsystem_path() { return _path; } - bool is_read_only() { return _read_only; } + char *subsystem_path() override { return _path; } + bool is_read_only() override { return _read_only; } +}; + +class CgroupV2CpuController: public CgroupCpuController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2CpuController(const CgroupV2Controller& reader) : _reader(reader) { + } + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + bool is_read_only() override { + return reader()->is_read_only(); + } +}; + +class CgroupV2MemoryController final: public CgroupMemoryController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2MemoryController(const CgroupV2Controller& reader) : _reader(reader) { + } + + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool is_read_only() override { + return reader()->is_read_only(); + } }; class CgroupV2Subsystem: public CgroupSubsystem { private: /* One unified controller */ - CgroupController* _unified = nullptr; + CgroupV2Controller _unified; /* Caching wrappers for cpu/memory metrics */ - CachingCgroupController* _memory = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _memory = nullptr; + CachingCgroupController* _cpu = nullptr; - jlong mem_swp_limit_val(); - jlong mem_swp_current_val(); + CgroupV2Controller* unified() { return &_unified; } public: - CgroupV2Subsystem(CgroupController * unified) { - _unified = unified; - _memory = new CachingCgroupController(unified); - _cpu = new CachingCgroupController(unified); + CgroupV2Subsystem(CgroupV2MemoryController* memory, + CgroupV2CpuController* cpu, + CgroupV2Controller unified) : + _unified(unified), + _memory(new CachingCgroupController(memory)), + _cpu(new CachingCgroupController(cpu)) { } - jlong read_memory_limit_in_bytes(); - int cpu_quota(); - int cpu_period(); - int cpu_shares(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_and_swap_usage_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); - jlong rss_usage_in_bytes(); - jlong cache_usage_in_bytes(); - - char * cpu_cpuset_cpus(); - char * cpu_cpuset_memory_nodes(); - jlong pids_max(); - jlong pids_current(); - - bool is_containerized(); - void print_version_specific_info(outputStream* st); - - const char * container_type() { + char * cpu_cpuset_cpus() override; + char * cpu_cpuset_memory_nodes() override; + jlong pids_max() override; + jlong pids_current() override; + + bool is_containerized() override; + + const char * container_type() override { return "cgroupv2"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() { return _memory; } + CachingCgroupController* cpu_controller() { return _cpu; } }; #endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP From a3479576c9b3e557cdc04e0984da6350e985dcc9 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 2 Jul 2024 18:13:50 +0000 Subject: [PATCH 53/85] 8335291: Problem list all SA core file tests on macosx-aarch64 due to JDK-8318754 Reviewed-by: kevinw, amenkov --- test/hotspot/jtreg/ProblemList.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 2d1311e3ac1..c55790de5ca 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -129,13 +129,13 @@ serviceability/jvmti/vthread/GetSetLocalTest/GetSetLocalTest.java 8286836 generi serviceability/jvmti/vthread/CarrierThreadEventNotification/CarrierThreadEventNotification.java 8333681 generic-all serviceability/dcmd/gc/RunFinalizationTest.java 8227120 generic-all -serviceability/sa/ClhsdbCDSCore.java 8267433 macosx-x64 -serviceability/sa/ClhsdbFindPC.java#xcomp-core 8267433 macosx-x64 -serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8267433 macosx-x64 -serviceability/sa/ClhsdbPmap.java#core 8267433 macosx-x64 -serviceability/sa/ClhsdbPstack.java#core 8267433 macosx-x64 -serviceability/sa/TestJmapCore.java 8267433 macosx-x64 -serviceability/sa/TestJmapCoreMetaspace.java 8267433 macosx-x64 +serviceability/sa/ClhsdbCDSCore.java 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbFindPC.java#xcomp-core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbPmap.java#core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbPstack.java#core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/TestJmapCore.java 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/TestJmapCoreMetaspace.java 8267433,8318754 macosx-x64,macosx-aarch64 serviceability/attach/ConcAttachTest.java 8290043 linux-all From 27982c8f5dad0e2d080846f803055c84bac9fddd Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 2 Jul 2024 20:27:52 +0000 Subject: [PATCH 54/85] 8327854: Test java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java failed with RuntimeException Reviewed-by: psandoz --- .../openjdk/tests/java/util/stream/WhileOpStatefulTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java index c980e17d05f..07348841b1e 100644 --- a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java @@ -256,7 +256,7 @@ private void testWhileMulti(Map>> sources, EXECUTION_TIME_LIMIT); return s.peek(e -> { if (!isWithinExecutionPeriod.getAsBoolean()) { - throw new RuntimeException(); + throw new RuntimeException("Execution time limit exceeded!"); } }); }); @@ -266,7 +266,7 @@ private void testWhileMulti(Map>> sources, return s.parallel() .peek(e -> { if (!isWithinExecutionPeriod.getAsBoolean()) { - throw new RuntimeException(); + throw new RuntimeException("Execution time limit exceeded!"); } }); }); From 1ef34c183315b70ddc27c177a2867e30132609f5 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 2 Jul 2024 23:15:31 +0000 Subject: [PATCH 55/85] 8335475: ClassBuilder incorrectly calculates max_locals in some cases Reviewed-by: asotona --- .../classfile/impl/StackMapGenerator.java | 2 +- test/jdk/jdk/classfile/StackMapsTest.java | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 0f1f6fb69de..5b103a21f8a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1046,7 +1046,7 @@ private void setLocalRawInternal(int index, Type type) { void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { int localsSize = 0; // Pre-emptively create a locals array that encompass all parameter slots - checkLocal(methodDesc.parameterCount() + (isStatic ? 0 : -1)); + checkLocal(methodDesc.parameterCount() + (isStatic ? -1 : 0)); if (!isStatic) { localsSize++; if (OBJECT_INITIALIZER_NAME.equals(name) && !CD_Object.equals(thisKlass.sym)) { diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index b3df31291bc..f72c237aa8f 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @summary Testing Classfile stack maps generator. - * @bug 8305990 8320222 8320618 + * @bug 8305990 8320222 8320618 8335475 * @build testdata.* * @run junit StackMapsTest */ @@ -36,6 +36,10 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static java.lang.constant.ConstantDescs.MTD_void; import static org.junit.jupiter.api.Assertions.*; import static helpers.TestUtil.assertEmpty; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -238,7 +242,7 @@ void testClassVersions() throws Exception { @Test void testInvalidAALOADStack() { ClassFile.of().build(ClassDesc.of("Test"), clb - -> clb.withMethodBody("test", ConstantDescs.MTD_void, 0, cob + -> clb.withMethodBody("test", MTD_void, 0, cob -> cob.bipush(10) .anewarray(ConstantDescs.CD_Object) .lconst_1() //long on stack caused NPE, see 8320618 @@ -312,4 +316,28 @@ void testInvalidStack() throws Exception { cb.pop(); }))); } + + @ParameterizedTest + @EnumSource(ClassFile.StackMapsOption.class) + void testEmptyCounters(ClassFile.StackMapsOption option) { + var cf = ClassFile.of(option); + var bytes = cf.build(ClassDesc.of("Test"), clb -> clb + .withMethodBody("a", MTD_void, ACC_STATIC, CodeBuilder::return_) + .withMethodBody("b", MTD_void, 0, CodeBuilder::return_) + ); + + var cm = ClassFile.of().parse(bytes); + for (var method : cm.methods()) { + var name = method.methodName(); + var code = method.code().orElseThrow(); + if (name.equalsString("a")) { + assertEquals(0, code.maxLocals()); // static method + assertEquals(0, code.maxStack()); + } else { + assertTrue(name.equalsString("b")); + assertEquals(1, code.maxLocals()); // instance method + assertEquals(0, code.maxStack()); + } + } + } } From f187c92befbe63e23b11eb0401e5095c44c24389 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 02:19:54 +0000 Subject: [PATCH 56/85] 8335370: Fix -Wzero-as-null-pointer-constant warning in jvmti_common.hpp Reviewed-by: jwaters, amenkov, sspitsyn --- test/lib/jdk/test/lib/jvmti/jvmti_common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp index 693baf98d1f..f16b9fefb99 100644 --- a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp +++ b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp @@ -239,7 +239,7 @@ print_method(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method, jint depth) { check_jvmti_status(jni, err, "print_method: error in JVMTI GetMethodName"); LOG("%2d: %s: %s%s\n", depth, cname, mname, msign); - fflush(0); + fflush(nullptr); deallocate(jvmti, jni, (void*)cname); deallocate(jvmti, jni, (void*)mname); deallocate(jvmti, jni, (void*)msign); From 3a2d426489ead9672512e0c5a6862284a54734ba Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:42:06 +0000 Subject: [PATCH 57/85] 8334726: Remove accidentally exposed individual methods from Class-File API Reviewed-by: asotona --- .../lang/classfile/attribute/ModuleAttribute.java | 12 +++--------- .../lang/classfile/components/CodeRelabeler.java | 10 +--------- .../classfile/constantpool/ConstantPoolBuilder.java | 10 +--------- .../internal/classfile/impl/CodeRelabelerImpl.java | 3 +-- .../classfile/impl/ModuleAttributeBuilderImpl.java | 3 +-- .../internal/classfile/impl/SplitConstantPool.java | 1 - .../classfile/impl/TemporaryConstantPool.java | 5 ----- 7 files changed, 7 insertions(+), 37 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 721719d2851..9a4c58478ad 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,7 +153,7 @@ static ModuleAttribute of(ModuleDesc moduleName, Consumer attrHandler) { var mb = new ModuleAttributeBuilderImpl(moduleName); attrHandler.accept(mb); - return mb.build(); + return mb.build(); } /** @@ -166,7 +166,7 @@ static ModuleAttribute of(ModuleEntry moduleName, Consumer attrHandler) { var mb = new ModuleAttributeBuilderImpl(moduleName); attrHandler.accept(mb); - return mb.build(); + return mb.build(); } /** @@ -319,11 +319,5 @@ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection op * @return this builder */ ModuleAttributeBuilder provides(ModuleProvideInfo provides); - - /** - * Builds module attribute. - * @return the module attribute - */ - ModuleAttribute build(); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java index a0ef4d4de9c..ca5ad90389c 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,12 +74,4 @@ static CodeRelabeler of(Map map) { static CodeRelabeler of(BiFunction mapFunction) { return new CodeRelabelerImpl(mapFunction); } - - /** - * Access method to internal re-labeling function. - * @param label source label - * @param codeBuilder builder to create new labels - * @return target label - */ - Label relabel(Label label, CodeBuilder codeBuilder); } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index db388c1c73b..a43e6f102ed 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,14 +92,6 @@ static ConstantPoolBuilder of() { */ boolean canWriteDirect(ConstantPool constantPool); - /** - * Writes associated bootstrap method entries to the specified writer - * - * @param buf the writer - * @return false when no bootstrap method entry has been written - */ - boolean writeBootstrapMethods(BufWriter buf); - /** * {@return A {@link Utf8Entry} describing the provided {@linkplain String}} * If a UTF8 entry in the pool already describes this string, it is returned; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java index f191cbf3c1f..e60a906e189 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ public record CodeRelabelerImpl(BiFunction mapFunction) implements CodeRelabeler { - @Override public Label relabel(Label label, CodeBuilder cob) { return mapFunction.apply(label, cob); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java index 1aad47cfd86..873b32e4ad6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,6 @@ public ModuleAttributeBuilderImpl(ModuleDesc moduleName) { this(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.name()))); } - @Override public ModuleAttribute build() { return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion, requires, exports, opens, uses, provides); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index b034328fdcc..6c5a8a266c0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -135,7 +135,6 @@ public boolean canWriteDirect(ConstantPool other) { return this == other || parent == other; } - @Override public boolean writeBootstrapMethods(BufWriter buf) { if (bsmSize == 0) return false; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java index 7b15489ace7..e5f7d9cca79 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java @@ -190,11 +190,6 @@ public boolean canWriteDirect(ConstantPool constantPool) { return false; } - @Override - public boolean writeBootstrapMethods(BufWriter buf) { - throw new UnsupportedOperationException(); - } - @Override public void writeTo(BufWriter buf) { throw new UnsupportedOperationException(); From 8a664a4c359deefd7237f3672b62d7d8c1ffb453 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:43:41 +0000 Subject: [PATCH 58/85] 8334734: Remove specialized readXxxEntry methods from ClassReader Reviewed-by: asotona --- .../java/lang/classfile/ClassReader.java | 75 ------------------- .../classfile/impl/AbstractInstruction.java | 8 +- .../classfile/impl/AnnotationReader.java | 13 ++-- .../classfile/impl/BoundAttribute.java | 41 +++++----- .../impl/BoundRecordComponentInfo.java | 6 +- .../internal/classfile/impl/ClassImpl.java | 2 +- .../classfile/impl/ClassReaderImpl.java | 69 +++++------------ .../internal/classfile/impl/FieldImpl.java | 6 +- .../internal/classfile/impl/MethodImpl.java | 6 +- 9 files changed, 58 insertions(+), 168 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java index 7b181180c6f..ef4a36729e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -27,10 +27,6 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolException; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.PackageEntry; import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.ClassReaderImpl; @@ -130,77 +126,6 @@ public sealed interface ClassReader extends ConstantPool */ T readEntryOrNull(int offset, Class cls); - /** - * {@return the UTF8 entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a UTF8 entry - */ - Utf8Entry readUtf8Entry(int offset); - - /** - * {@return the UTF8 entry whose index is given at the specified - * offset within the classfile, or null if the index at the specified - * offset is zero} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or the index does not correspond to - * a UTF8 entry - */ - Utf8Entry readUtf8EntryOrNull(int offset); - - /** - * {@return the module entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a module entry - */ - ModuleEntry readModuleEntry(int offset); - - /** - * {@return the package entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a package entry - */ - PackageEntry readPackageEntry(int offset); - - /** - * {@return the class entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a class entry - */ - ClassEntry readClassEntry(int offset); - - /** - * {@return the name-and-type entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a name-and-type entry - */ - NameAndTypeEntry readNameAndTypeEntry(int offset); - - /** - * {@return the method handle entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a method handle entry - */ - MethodHandleEntry readMethodHandleEntry(int offset); - /** * {@return the unsigned byte at the specified offset within the classfile} * @param offset the offset within the classfile diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 0e528cd01fd..48e1f0990b2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -529,7 +529,7 @@ public static final class BoundNewObjectInstruction @Override public ClassEntry className() { if (classEntry == null) - classEntry = code.classReader.readClassEntry(pos + 1); + classEntry = code.classReader.readEntry(pos + 1, ClassEntry.class); return classEntry; } @@ -576,7 +576,7 @@ public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) { @Override public ClassEntry componentType() { - return code.classReader.readClassEntry(pos + 1); + return code.classReader.readEntry(pos + 1, ClassEntry.class); } @Override @@ -607,7 +607,7 @@ public int dimensions() { @Override public ClassEntry arrayType() { - return code.classReader.readClassEntry(pos + 1); + return code.classReader.readEntry(pos + 1, ClassEntry.class); } @Override @@ -636,7 +636,7 @@ public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) { @Override public ClassEntry type() { if (typeEntry == null) - typeEntry = code.classReader.readClassEntry(pos + 1); + typeEntry = code.classReader.readEntry(pos + 1, ClassEntry.class); return typeEntry; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index c082878abd4..7b5920b3e78 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -66,9 +66,10 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p)); - case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2)); - case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p)); + case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); + case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), + classReader.readEntry(p + 2, Utf8Entry.class)); + case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); case AEV_ARRAY -> { int numValues = classReader.readU2(p); @@ -127,7 +128,7 @@ private static int skipElementValue(ClassReader classReader, int p) { } private static Annotation readAnnotation(ClassReader classReader, int p) { - Utf8Entry annotationClass = classReader.entryByIndex(classReader.readU2(p), Utf8Entry.class); + Utf8Entry annotationClass = classReader.readEntry(p, Utf8Entry.class); p += 2; List elems = readAnnotationElementValuePairs(classReader, p); return new AnnotationImpl(annotationClass, elems); @@ -150,7 +151,7 @@ private static List readAnnotationElementValuePairs(ClassRead p += 2; var annotationElements = new Object[numElementValuePairs]; for (int i = 0; i < numElementValuePairs; ++i) { - Utf8Entry elementName = classReader.readUtf8Entry(p); + Utf8Entry elementName = classReader.readEntry(p, Utf8Entry.class); p += 2; AnnotationValue value = readElementValue(classReader, p); annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value); @@ -239,7 +240,7 @@ private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, }; } // the annotation info for this annotation - Utf8Entry type = classReader.readUtf8Entry(p); + Utf8Entry type = classReader.readEntry(p, Utf8Entry.class); p += 2; return TypeAnnotation.of(targetInfo, List.of(typePath), type, readAnnotationElementValuePairs(classReader, p)); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index 45e0c092c3e..21a01becec2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -135,7 +135,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla int cfLen = reader.classfileLength(); var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption(); for (int i = 0; i < size; ++i) { - Utf8Entry name = reader.readUtf8Entry(p); + Utf8Entry name = reader.readEntry(p, Utf8Entry.class); int len = reader.readInt(p + 2); p += 6; if (len < 0 || len > cfLen - p) { @@ -347,7 +347,7 @@ public List parameters() { int p = payloadStart + 1; int pEnd = p + (cnt * 4); for (int i = 0; p < pEnd; p += 4, i++) { - Utf8Entry name = classReader.readUtf8EntryOrNull(p); + Utf8Entry name = classReader.readEntryOrNull(p, Utf8Entry.class); int accessFlags = classReader.readU2(p + 2); elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags); } @@ -367,7 +367,7 @@ public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper hashes() { int p = payloadStart + 4; //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt); for (int i = 0; i < cnt; ++i) { - ModuleEntry module = classReader.readModuleEntry(p); + ModuleEntry module = classReader.readEntry(p, ModuleEntry.class); int hashLength = classReader.readU2(p + 2); //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength); p += 4; @@ -430,7 +430,7 @@ public BoundSignatureAttribute(ClassReader cf, AttributeMapper @Override public ClassEntry nestHost() { - return classReader.readClassEntry(payloadStart); + return classReader.readEntry(payloadStart, ClassEntry.class); } } @@ -498,7 +498,7 @@ public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper @Override public Utf8Entry sourceId() { - return classReader.readUtf8Entry(payloadStart); + return classReader.readEntry(payloadStart, Utf8Entry.class); } } @@ -569,7 +569,7 @@ public BoundModuleAttribute(ClassReader cf, AttributeMapper map @Override public ModuleEntry moduleName() { - return classReader.readModuleEntry(payloadStart); + return classReader.readEntry(payloadStart, ModuleEntry.class); } @Override @@ -579,7 +579,7 @@ public int moduleFlagsMask() { @Override public Optional moduleVersion() { - return Optional.ofNullable(classReader.readUtf8EntryOrNull(payloadStart + 4)); + return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 4, Utf8Entry.class)); } @Override @@ -630,7 +630,7 @@ private void structure() { ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt]; int end = p + (cnt * 6); for (int i = 0; p < end; p += 6, i++) { - elements[i] = ModuleRequireInfo.of(classReader.readModuleEntry(p), + elements[i] = ModuleRequireInfo.of(classReader.readEntry(p, ModuleEntry.class), classReader.readU2(p + 2), classReader.readEntryOrNull(p + 4, Utf8Entry.class)); } @@ -642,7 +642,7 @@ private void structure() { p += 2; ModuleExportInfo[] elements = new ModuleExportInfo[cnt]; for (int i = 0; i < cnt; i++) { - PackageEntry pe = classReader.readPackageEntry(p); + PackageEntry pe = classReader.readEntry(p, PackageEntry.class); int exportFlags = classReader.readU2(p + 2); p += 4; List exportsTo = readEntryList(p); @@ -657,7 +657,7 @@ private void structure() { p += 2; ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt]; for (int i = 0; i < cnt; i++) { - PackageEntry po = classReader.readPackageEntry(p); + PackageEntry po = classReader.readEntry(p, PackageEntry.class); int opensFlags = classReader.readU2(p + 2); p += 4; List opensTo = readEntryList(p); @@ -675,7 +675,7 @@ private void structure() { ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt]; provides = new ArrayList<>(cnt); for (int i = 0; i < cnt; i++) { - ClassEntry c = classReader.readClassEntry(p); + ClassEntry c = classReader.readEntry(p, ClassEntry.class); p += 2; List providesWith = readEntryList(p); p += 2 + providesWith.size() * 2; @@ -743,8 +743,7 @@ public List bootstrapMethods() { BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size]; int p = payloadStart + 2; for (int i = 0; i < size; ++i) { - final AbstractPoolEntry.MethodHandleEntryImpl handle - = (AbstractPoolEntry.MethodHandleEntryImpl) classReader.readMethodHandleEntry(p); + final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class); final List args = readEntryList(p + 2); p += 4 + args.size() * 2; int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args); @@ -771,7 +770,7 @@ public List classes() { int p = payloadStart + 2; InnerClassInfo[] elements = new InnerClassInfo[cnt]; for (int i = 0; i < cnt; i++) { - ClassEntry innerClass = classReader.readClassEntry(p); + ClassEntry innerClass = classReader.readEntry(p, ClassEntry.class); var outerClass = classReader.readEntryOrNull(p + 2, ClassEntry.class); var innerName = classReader.readEntryOrNull(p + 4, Utf8Entry.class); int flags = classReader.readU2(p + 6); @@ -792,7 +791,7 @@ public BoundEnclosingMethodAttribute(ClassReader cf, AttributeMapper interfaces() { pos += 2; var arr = new Object[cnt]; for (int i = 0; i < cnt; ++i) { - arr[i] = reader.readClassEntry(pos); + arr[i] = reader.readEntry(pos, ClassEntry.class); pos += 2; } this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(arr); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index b8a262ce41c..25d4e2e68e8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -151,7 +151,7 @@ public int flags() { @Override public ClassEntry thisClassEntry() { if (thisClass == null) { - thisClass = readClassEntry(thisClassPos); + thisClass = readEntry(thisClassPos, ClassEntry.class); } return thisClass; } @@ -395,23 +395,23 @@ public T entryByIndex(int index, Class cls) { case TAG_FLOAT -> new AbstractPoolEntry.FloatEntryImpl(this, index, readFloat(q)); case TAG_LONG -> new AbstractPoolEntry.LongEntryImpl(this, index, readLong(q)); case TAG_DOUBLE -> new AbstractPoolEntry.DoubleEntryImpl(this, index, readDouble(q)); - case TAG_CLASS -> new AbstractPoolEntry.ClassEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_STRING -> new AbstractPoolEntry.StringEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_FIELDREF -> new AbstractPoolEntry.FieldRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q), - (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q + 2)); + case TAG_CLASS -> new AbstractPoolEntry.ClassEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_STRING -> new AbstractPoolEntry.StringEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_FIELDREF -> new AbstractPoolEntry.FieldRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.Utf8EntryImpl.class)); case TAG_METHODHANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), readEntry(q + 1, AbstractPoolEntry.AbstractMemberRefEntry.class)); - case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); default -> throw new ConstantPoolException( "Bad tag (" + tag + ") at index (" + index + ") position (" + offset + ")"); }; @@ -428,7 +428,7 @@ public int skipAttributeHolder(int offset) { int len = readInt(p + 2); p += 6; if (len < 0 || len > classfileLength - p) { - throw new IllegalArgumentException("attribute " + readUtf8Entry(p - 6).stringValue() + " too big to handle"); + throw new IllegalArgumentException("attribute " + readEntry(p - 6, Utf8Entry.class).stringValue() + " too big to handle"); } p += len; } @@ -465,41 +465,6 @@ public T readEntryOrNull(int offset, Class cls) { return entryByIndex(index, cls); } - @Override - public Utf8Entry readUtf8Entry(int pos) { - return readEntry(pos, Utf8Entry.class); - } - - @Override - public Utf8Entry readUtf8EntryOrNull(int pos) { - return readEntryOrNull(pos, Utf8Entry.class); - } - - @Override - public ModuleEntry readModuleEntry(int pos) { - return readEntry(pos, ModuleEntry.class); - } - - @Override - public PackageEntry readPackageEntry(int pos) { - return readEntry(pos, PackageEntry.class); - } - - @Override - public ClassEntry readClassEntry(int pos) { - return readEntry(pos, ClassEntry.class); - } - - @Override - public NameAndTypeEntry readNameAndTypeEntry(int pos) { - return readEntry(pos, NameAndTypeEntry.class); - } - - @Override - public MethodHandleEntry readMethodHandleEntry(int pos) { - return readEntry(pos, MethodHandleEntry.class); - } - @Override public boolean compare(BufWriter bufWriter, int bufWriterOffset, diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index 6645ddb9396..fb072ae5638 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,12 +61,12 @@ public Optional parent() { @Override public Utf8Entry fieldName() { - return reader.readUtf8Entry(startPos + 2); + return reader.readEntry(startPos + 2, Utf8Entry.class); } @Override public Utf8Entry fieldType() { - return reader.readUtf8Entry(startPos + 4); + return reader.readEntry(startPos + 4, Utf8Entry.class); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 9a96e586c55..3bc811634ee 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,12 +64,12 @@ public Optional parent() { @Override public Utf8Entry methodName() { - return reader.readUtf8Entry(startPos + 2); + return reader.readEntry(startPos + 2, Utf8Entry.class); } @Override public Utf8Entry methodType() { - return reader.readUtf8Entry(startPos + 4); + return reader.readEntry(startPos + 4, Utf8Entry.class); } @Override From f7af4504a804711d93208b763b3e41eafcf61735 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:49:43 +0000 Subject: [PATCH 59/85] 8335110: Fix instruction name and API spec inconsistencies in CodeBuilder Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 114 +++++++++++++++++- .../classfile/attribute/CodeAttribute.java | 6 +- .../java/lang/runtime/SwitchBootstraps.java | 2 +- .../internal/classfile/impl/LabelImpl.java | 2 +- .../jfr/internal/EventInstrumentation.java | 8 +- .../helpers/RebuildingTransformation.java | 4 +- 6 files changed, 120 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index e954be079fa..cffa560bef3 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,6 +97,27 @@ * #with(ClassFileElement)} or concretely by calling the various {@code withXxx} * methods. * + *

Instruction Factories

+ * {@code CodeBuilder} provides convenience methods to create instructions (See + * JVMS {@jvms 6.5} Instructions) by their mnemonic, taking necessary operands. + *
    + *
  • Instructions that encode their operands in their opcode, such as {@code + * aload_}, share their factories with their generic version like {@link + * #aload aload}. Note that some constant instructions, such as {@link #iconst_1 + * iconst_1}, do not have generic versions, and thus have their own factories. + *
  • Instructions that accept wide operands, such as {@code ldc2_w} or {@code + * wide}, share their factories with their regular version like {@link #ldc}. Note + * that {@link #goto_w goto_w} has its own factory to avoid {@linkplain + * ClassFile.ShortJumpsOption short jumps}. + *
  • The {@code goto}, {@code instanceof}, {@code new}, and {@code return} + * instructions' factories are named {@link #goto_ goto_}, {@link #instanceOf + * instanceOf}, {@link #new_ new_}, and {@link #return_() return_} respectively, + * due to clashes with keywords in the Java programming language. + *
  • Factories are not provided for instructions {@code jsr}, {@code jsr_w}, + * {@code ret}, and {@code wide ret}, which cannot appear in class files with + * major version {@value ClassFile#JAVA_7_VERSION} or higher. (JVMS {@jvms 4.9.1}) + *
+ * * @see CodeTransform * * @since 22 @@ -130,7 +151,7 @@ public sealed interface CodeBuilder /** * {@return the local variable slot associated with the receiver}. * - * @throws IllegalStateException if this is not a static method + * @throws IllegalStateException if this is a static method */ int receiverSlot(); @@ -699,7 +720,7 @@ default CodeBuilder lineNumber(int line) { * @return this builder */ default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassEntry catchType) { - return with(ExceptionCatch.of(handler, start, end, Optional.of(catchType))); + return with(ExceptionCatch.of(handler, start, end, Optional.ofNullable(catchType))); } /** @@ -837,6 +858,10 @@ default CodeBuilder aastore() { /** * Generate an instruction to load a reference from a local variable + * + *

This may also generate {@code aload_} and + * {@code wide aload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -881,6 +906,10 @@ default CodeBuilder arraylength() { /** * Generate an instruction to store a reference into a local variable + * + *

This may also generate {@code astore_} and + * {@code wide astore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1046,6 +1075,10 @@ default CodeBuilder ddiv() { /** * Generate an instruction to load a double from a local variable + * + *

This may also generate {@code dload_} and + * {@code wide dload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1087,6 +1120,10 @@ default CodeBuilder dreturn() { /** * Generate an instruction to store a double into a local variable + * + *

This may also generate {@code dstore_} and + * {@code wide dstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1250,6 +1287,10 @@ default CodeBuilder fdiv() { /** * Generate an instruction to load a float from a local variable + * + *

This may also generate {@code fload_} and + * {@code wide fload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1291,6 +1332,10 @@ default CodeBuilder freturn() { /** * Generate an instruction to store a float into a local variable + * + *

This may also generate {@code fstore_} and + * {@code wide fstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1350,6 +1395,15 @@ default CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) { /** * Generate an instruction to branch always + * + *

This may also generate {@code goto_w} instructions if the {@link + * ClassFile.ShortJumpsOption#FIX_SHORT_JUMPS FIX_SHORT_JUMPS} option + * is set. + * + * @apiNote The instruction's name is {@code goto}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param target the branch target * @return this builder */ @@ -1587,7 +1641,7 @@ default CodeBuilder if_icmpne(Label target) { * @param target the branch target * @return this builder */ - default CodeBuilder if_nonnull(Label target) { + default CodeBuilder ifnonnull(Label target) { return branch(Opcode.IFNONNULL, target); } @@ -1596,7 +1650,7 @@ default CodeBuilder if_nonnull(Label target) { * @param target the branch target * @return this builder */ - default CodeBuilder if_null(Label target) { + default CodeBuilder ifnull(Label target) { return branch(Opcode.IFNULL, target); } @@ -1666,6 +1720,10 @@ default CodeBuilder iinc(int slot, int val) { /** * Generate an instruction to load an int from a local variable + * + *

This may also generate {@code iload_} and + * {@code wide iload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1691,6 +1749,11 @@ default CodeBuilder ineg() { /** * Generate an instruction to determine if an object is of the given type + * + * @apiNote The instruction's name is {@code instanceof}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with camel case instead. + * * @param target the target type * @return this builder * @since 23 @@ -1701,6 +1764,11 @@ default CodeBuilder instanceOf(ClassEntry target) { /** * Generate an instruction to determine if an object is of the given type + * + * @apiNote The instruction's name is {@code instanceof}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with camel case instead. + * * @param target the target type * @return this builder * @throws IllegalArgumentException if {@code target} represents a primitive type @@ -1910,6 +1978,10 @@ default CodeBuilder ishr() { /** * Generate an instruction to store an int into a local variable + * + *

This may also generate {@code istore_} and + * {@code wide istore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2033,6 +2105,12 @@ default CodeBuilder lconst_1() { /** * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * + *

This may also generate {@code ldc_w} and {@code ldc2_w} instructions. + * + * @apiNote {@link #loadConstant(ConstantDesc) loadConstant} generates more optimal instructions + * and should be used for general constants if an {@code ldc} instruction is not strictly required. + * * @param value the constant value * @return this builder */ @@ -2042,6 +2120,9 @@ default CodeBuilder ldc(ConstantDesc value) { /** * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * + *

This may also generate {@code ldc_w} and {@code ldc2_w} instructions. + * * @param entry the constant value * @return this builder */ @@ -2062,6 +2143,10 @@ default CodeBuilder ldiv() { /** * Generate an instruction to load a long from a local variable + * + *

This may also generate {@code lload_} and + * {@code wide lload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2127,6 +2212,10 @@ default CodeBuilder lshr() { /** * Generate an instruction to store a long into a local variable + * + *

This may also generate {@code lstore_} and + * {@code wide lstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2197,6 +2286,11 @@ default CodeBuilder multianewarray(ClassDesc array, int dims) { /** * Generate an instruction to create a new object + * + * @apiNote The instruction's name is {@code new}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param clazz the new class type * @return this builder */ @@ -2206,6 +2300,11 @@ default CodeBuilder new_(ClassEntry clazz) { /** * Generate an instruction to create a new object + * + * @apiNote The instruction's name is {@code new}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param clazz the new class type * @return this builder * @throws IllegalArgumentException if {@code clazz} represents a primitive type @@ -2283,6 +2382,11 @@ default CodeBuilder putstatic(ClassDesc owner, String name, ClassDesc type) { /** * Generate an instruction to return void from the method + * + * @apiNote The instruction's name is {@code return}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @return this builder */ default CodeBuilder return_() { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index 1a57cf4f37f..02cbcee810f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,9 +58,9 @@ public sealed interface CodeAttribute extends Attribute, CodeMode byte[] codeArray(); /** - * {@return the position of the {@code Label} in the {@code codeArray} - * or -1 if the {@code Label} does not point to the {@code codeArray}} + * {@return the position of the {@code label} in the {@link #codeArray codeArray}} * @param label a marker for a position within this {@code CodeAttribute} + * @throws IllegalArgumentException if the {@code label} is not from this attribute */ int labelToBci(Label label); } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 24ee48c1f47..ccb33a0e4db 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -422,7 +422,7 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto cb.pop(); cb.aload(SELECTOR_OBJ); Label nonNullLabel = cb.newLabel(); - cb.if_nonnull(nonNullLabel); + cb.ifnonnull(nonNullLabel); cb.iconst_m1(); cb.ireturn(); cb.labelBinding(nonNullLabel); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java index b316c5a6dd1..2aaf5f033c0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java @@ -51,7 +51,7 @@ public final class LabelImpl private final LabelContext labelContext; private int bci; - public LabelImpl(LabelContext labelContext, int bci) { + public LabelImpl(LabelContext labelContext, int bci) { this.labelContext = Objects.requireNonNull(labelContext); this.bci = bci; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index cf7e162a42e..d8f5e689ca1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -461,7 +461,7 @@ private void makeInstrumented() { catchAllHandler.dup(); // stack: [ex] [EW] [EW] Label rethrow = catchAllHandler.newLabel(); - catchAllHandler.if_null(rethrow); + catchAllHandler.ifnull(rethrow); // stack: [ex] [EW] catchAllHandler.dup(); // stack: [ex] [EW] [EW] @@ -486,7 +486,7 @@ private void makeInstrumented() { Label fail = codeBuilder.newLabel(); if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.if_null(fail); + codeBuilder.ifnull(fail); } // if (!eventConfiguration.shouldCommit(duration) goto fail; getEventConfiguration(codeBuilder); @@ -525,7 +525,7 @@ private void makeInstrumented() { if (guardEventConfiguration) { // if (eventConfiguration == null) goto fail; getEventConfiguration(codeBuilder); - codeBuilder.if_null(fail); + codeBuilder.ifnull(fail); } // return eventConfiguration.shouldCommit(duration); getEventConfiguration(codeBuilder); @@ -738,7 +738,7 @@ private void updateEnabledMethod(MethodDesc method) { Label nullLabel = codeBuilder.newLabel(); if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.if_null(nullLabel); + codeBuilder.ifnull(nullLabel); } getEventConfiguration(codeBuilder); invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 0c9b771c3ef..7905a79fd40 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -257,8 +257,8 @@ public void accept(CodeBuilder cob, CodeElement coe) { case IF_ICMPLE -> cob.if_icmple(target); case IF_ICMPLT -> cob.if_icmplt(target); case IF_ICMPNE -> cob.if_icmpne(target); - case IFNONNULL -> cob.if_nonnull(target); - case IFNULL -> cob.if_null(target); + case IFNONNULL -> cob.ifnonnull(target); + case IFNULL -> cob.ifnull(target); case IFEQ -> cob.ifeq(target); case IFGE -> cob.ifge(target); case IFGT -> cob.ifgt(target); From f9b4ea13e693da268c9aee27dee49f9c7f798bb1 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Jul 2024 02:56:17 +0000 Subject: [PATCH 60/85] 8334220: Optimize Klass layout after JDK-8180450 Reviewed-by: coleenp, stuefe, dholmes --- src/hotspot/share/oops/klass.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 2923235e2f3..6ec6ac889be 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -159,11 +159,6 @@ class Klass : public Metadata { // Provide access the corresponding instance java.lang.ClassLoader. ClassLoaderData* _class_loader_data; - // Bitmap and hash code used by hashed secondary supers. - uintx _bitmap; - uint8_t _hash_slot; - - static uint8_t compute_hash_slot(Symbol* s); int _vtable_len; // vtable length. This field may be read very often when we // have lots of itable dispatches (e.g., lambdas and streams). @@ -173,6 +168,10 @@ class Klass : public Metadata { JFR_ONLY(DEFINE_TRACE_ID_FIELD;) + // Bitmap and hash code used by hashed secondary supers. + uintx _bitmap; + uint8_t _hash_slot; + private: // This is an index into FileMapHeader::_shared_path_table[], to // associate this class with the JAR file where it's loaded from during @@ -392,6 +391,7 @@ class Klass : public Metadata { void set_next_sibling(Klass* s); private: + static uint8_t compute_hash_slot(Symbol* s); static void hash_insert(Klass* klass, GrowableArray* secondaries, uintx& bitmap); static uintx hash_secondary_supers(Array* secondaries, bool rewrite); From fac74b118f5fda4ec297e46238d34ce5b9be1e21 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Jul 2024 03:01:06 +0000 Subject: [PATCH 61/85] 8334229: Optimize InterpreterOopMap layout Reviewed-by: coleenp, dholmes --- src/hotspot/share/interpreter/oopMapCache.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index a3f5c395f58..7037b2c7d1f 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -83,21 +83,21 @@ 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 (USHRT_MAX if invalid) int _expression_stack_size; // the size of the expression stack in slots + unsigned short _bci; // the bci for which the mask is valid protected: +#ifdef ASSERT + bool _resource_allocate_bit_mask; +#endif + int _num_oops; intptr_t _bit_mask[N]; // the bit mask if // mask_size <= small_mask_limit, // ptr to bit mask otherwise // "protected" so that sub classes can // access it without using trickery in // method bit_mask(). - int _num_oops; -#ifdef ASSERT - bool _resource_allocate_bit_mask; -#endif // access methods Method* method() const { return _method; } From d51141e5fc84f9f933e78d0eb25af86e41798ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 3 Jul 2024 04:36:32 +0000 Subject: [PATCH 62/85] 8321274: Rename ZipEntry.extraAttributes to ZipEntry.externalFileAttributes Reviewed-by: lancea, jpai --- .../share/classes/java/util/zip/ZipEntry.java | 4 +-- .../share/classes/java/util/zip/ZipFile.java | 10 +++---- .../java/util/zip/ZipOutputStream.java | 4 +-- .../access/JavaUtilZipFileAccess.java | 6 ++--- .../jdk/security/jarsigner/JarSigner.java | 16 +++++------- .../sun/security/tools/jarsigner/Main.java | 14 +++++----- .../security/tools/jarsigner/Resources.java | 4 +-- .../tools/jarsigner/Resources_de.java | 4 +-- .../tools/jarsigner/Resources_ja.java | 4 +-- .../tools/jarsigner/Resources_zh_CN.java | 4 +-- .../classes/jdk/nio/zipfs/ZipFileSystem.java | 26 +++++++++---------- .../security/tools/jarsigner/SymLinkTest.java | 12 ++++----- 12 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index 85bd6155fa8..d97760d950a 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -59,7 +59,7 @@ public class ZipEntry implements ZipConstants, Cloneable { int flag = 0; // general purpose flag byte[] extra; // optional extra field data for entry String comment; // optional comment string for entry - int extraAttributes = -1; // e.g. POSIX permissions, sym links. + int externalFileAttributes = -1; // File type, setuid, setgid, sticky, POSIX permissions /** * Compression method for uncompressed entries. */ @@ -134,7 +134,7 @@ public ZipEntry(ZipEntry e) { flag = e.flag; extra = e.extra; comment = e.comment; - extraAttributes = e.extraAttributes; + externalFileAttributes = e.externalFileAttributes; } /** diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 4f4c410a83e..da8ab730873 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -697,7 +697,7 @@ private ZipEntry getZipEntry(String name, int pos) { e.method = CENHOW(cen, pos); if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) { // read all bits in this field, including sym link attributes - e.extraAttributes = CENATX_PERMS(cen, pos) & 0xFFFF; + e.externalFileAttributes = CENATX_PERMS(cen, pos) & 0xFFFF; } if (elen != 0) { @@ -1165,12 +1165,12 @@ public Stream entryNameStream(ZipFile zip) { return zip.entryNameStream(); } @Override - public int getExtraAttributes(ZipEntry ze) { - return ze.extraAttributes; + public int getExternalFileAttributes(ZipEntry ze) { + return ze.externalFileAttributes; } @Override - public void setExtraAttributes(ZipEntry ze, int extraAttrs) { - ze.extraAttributes = extraAttrs; + public void setExternalFileAttributes(ZipEntry ze, int externalFileAttributes) { + ze.externalFileAttributes = externalFileAttributes; } } diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index e1d40355860..231e6629a54 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -541,7 +541,7 @@ private void writeEXT(ZipEntry e) throws IOException { * to a version value. */ private int versionMadeBy(ZipEntry e, int version) { - return (e.extraAttributes < 0) ? version : + return (e.externalFileAttributes < 0) ? version : VERSION_MADE_BY_BASE_UNIX | (version & 0xff); } @@ -637,7 +637,7 @@ private void writeCEN(XEntry xentry) throws IOException { writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) // extra file attributes, used for storing posix permissions etc. - writeInt(e.extraAttributes > 0 ? e.extraAttributes << 16 : 0); + writeInt(e.externalFileAttributes > 0 ? e.externalFileAttributes << 16 : 0); writeInt(offset); // relative offset of local header writeBytes(nameBytes, 0, nameBytes.length); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java index 3728a6c70d4..2c9d904005d 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public interface JavaUtilZipFileAccess { public Enumeration entries(ZipFile zip); public Stream stream(ZipFile zip); public Stream entryNameStream(ZipFile zip); - public void setExtraAttributes(ZipEntry ze, int extraAttrs); - public int getExtraAttributes(ZipEntry ze); + public void setExternalFileAttributes(ZipEntry ze, int externalFileAttributes); + public int getExternalFileAttributes(ZipEntry ze); } diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 5dbaf6041ee..3ff0f2663a2 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.PKCS9Attributes; import sun.security.timestamp.HttpTimestamper; -import sun.security.tools.PathList; import sun.security.util.Event; import sun.security.util.ManifestDigester; import sun.security.util.SignatureFileVerifier; @@ -39,11 +38,8 @@ import sun.security.x509.AlgorithmId; import java.io.*; -import java.lang.reflect.InvocationTargetException; import java.net.SocketTimeoutException; import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; import java.security.*; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -492,7 +488,7 @@ public JarSigner build() { private final String tSADigestAlg; private final boolean sectionsonly; // do not "sign" the whole manifest private final boolean internalsf; // include the .SF inside the PKCS7 block - private boolean extraAttrsDetected; + private boolean externalFileAttributesDetected; private JarSigner(JarSigner.Builder builder) { @@ -936,12 +932,12 @@ private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze) ze2.setTime(ze.getTime()); ze2.setComment(ze.getComment()); ze2.setExtra(ze.getExtra()); - int extraAttrs = JUZFA.getExtraAttributes(ze); - if (!extraAttrsDetected && extraAttrs != -1) { - extraAttrsDetected = true; + int externalFileAttributes = JUZFA.getExternalFileAttributes(ze); + if (!externalFileAttributesDetected && externalFileAttributes != -1) { + externalFileAttributesDetected = true; Event.report(Event.ReporterCategory.ZIPFILEATTRS, "detected"); } - JUZFA.setExtraAttributes(ze2, extraAttrs); + JUZFA.setExternalFileAttributes(ze2, externalFileAttributes); if (ze.getMethod() == ZipEntry.STORED) { ze2.setSize(ze.getSize()); ze2.setCrc(ze.getCrc()); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index e011145632d..78a03a4332d 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ public class Main { private static final Set SIG_PRIMITIVE_SET = Collections .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); - private static boolean extraAttrsDetected; + private static boolean externalFileAttributesDetected; static final String VERSION = "1.0"; @@ -823,8 +823,8 @@ void verifyJar(String jarName) JarEntry je = e.nextElement(); String name = je.getName(); - if (!extraAttrsDetected && JUZFA.getExtraAttributes(je) != -1) { - extraAttrsDetected = true; + if (!externalFileAttributesDetected && JUZFA.getExternalFileAttributes(je) != -1) { + externalFileAttributesDetected = true; } hasSignature |= signatureRelated(name) && SignatureFileVerifier.isBlockOrSF(name); @@ -1311,8 +1311,8 @@ private void displayMessagesAndResult(boolean isSigning) { } } - if (extraAttrsDetected) { - warnings.add(rb.getString("extra.attributes.detected")); + if (externalFileAttributesDetected) { + warnings.add(rb.getString("external.file.attributes.detected")); } if ((strict) && (!errors.isEmpty())) { @@ -1946,7 +1946,7 @@ void signJar(String jarName, String alias) try { Event.setReportListener(Event.ReporterCategory.ZIPFILEATTRS, - (t, o) -> extraAttrsDetected = true); + (t, o) -> externalFileAttributesDetected = true); builder.build().sign(zipFile, fos); } catch (JarSignerException e) { failedCause = e.getCause(); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index d982f618600..6a86b72ad1b 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-bit key (disabled)"}, {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, - {"extra.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, + {"external.file.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java index 06c8a901cd2..b11c491be14 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_de extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-Bit-Schl\u00FCssel (deaktiviert)"}, {"key.bit.eccurve.disabled", "%1$d-Bit-%2$s-Schl\u00FCssel (deaktiviert)"}, {"unknown.size", "unbekannte Gr\u00F6\u00DFe"}, - {"extra.attributes.detected", "POSIX-Dateiberechtigung und/oder Symlink-Attribute erkannt. Diese Attribute werden bei der Signatur ignoriert und sind nicht durch die Signatur gesch\u00FCtzt."}, + {"external.file.attributes.detected", "POSIX-Dateiberechtigung und/oder Symlink-Attribute erkannt. Diese Attribute werden bei der Signatur ignoriert und sind nicht durch die Signatur gesch\u00FCtzt."}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java index 1d8e7c54a3c..3754d864ce1 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_ja extends java.util.ListResourceBundle { {"key.bit.disabled", "%d\u30D3\u30C3\u30C8\u30FB\u30AD\u30FC (\u7121\u52B9)"}, {"key.bit.eccurve.disabled", "%1$d\u30D3\u30C3\u30C8%2$s\u30AD\u30FC(\u7121\u52B9)"}, {"unknown.size", "\u4E0D\u660E\u30B5\u30A4\u30BA"}, - {"extra.attributes.detected", "POSIX\u30D5\u30A1\u30A4\u30EB\u6A29\u9650\u307E\u305F\u306Fsymlink(\u3042\u308B\u3044\u306F\u305D\u306E\u4E21\u65B9)\u306E\u5C5E\u6027\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u3002\u7F72\u540D\u4E2D\u306F\u3053\u308C\u3089\u306E\u5C5E\u6027\u306F\u7121\u8996\u3055\u308C\u3001\u7F72\u540D\u306B\u3088\u3063\u3066\u4FDD\u8B77\u3055\u308C\u307E\u305B\u3093\u3002"}, + {"external.file.attributes.detected", "POSIX\u30D5\u30A1\u30A4\u30EB\u6A29\u9650\u307E\u305F\u306Fsymlink(\u3042\u308B\u3044\u306F\u305D\u306E\u4E21\u65B9)\u306E\u5C5E\u6027\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u3002\u7F72\u540D\u4E2D\u306F\u3053\u308C\u3089\u306E\u5C5E\u6027\u306F\u7121\u8996\u3055\u308C\u3001\u7F72\u540D\u306B\u3088\u3063\u3066\u4FDD\u8B77\u3055\u308C\u307E\u305B\u3093\u3002"}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java index 2b4059ea877..9e76346fca2 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_zh_CN extends java.util.ListResourceBundle { {"key.bit.disabled", "%d \u4F4D\u5BC6\u94A5\uFF08\u7981\u7528\uFF09"}, {"key.bit.eccurve.disabled", "%1$d \u4F4D %2$s \u5BC6\u94A5\uFF08\u7981\u7528\uFF09"}, {"unknown.size", "\u672A\u77E5\u5927\u5C0F"}, - {"extra.attributes.detected", "\u68C0\u6D4B\u5230 POSIX \u6587\u4EF6\u6743\u9650\u548C/\u6216 symlink \u5C5E\u6027\u3002\u8FD9\u4E9B\u5C5E\u6027\u5728\u8FDB\u884C\u7B7E\u540D\u65F6\u4F1A\u88AB\u5FFD\u7565\uFF0C\u4E0D\u53D7\u8BE5\u7B7E\u540D\u7684\u4FDD\u62A4\u3002"}, + {"external.file.attributes.detected", "\u68C0\u6D4B\u5230 POSIX \u6587\u4EF6\u6743\u9650\u548C/\u6216 symlink \u5C5E\u6027\u3002\u8FD9\u4E9B\u5C5E\u6027\u5728\u8FDB\u884C\u7B7E\u540D\u65F6\u4F1A\u88AB\u5FFD\u7565\uFF0C\u4E0D\u53D7\u8BE5\u7B7E\u540D\u7684\u4FDD\u62A4\u3002"}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index cecb8b86a2d..5e5b665790f 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -645,12 +645,12 @@ void setPermissions(byte[] path, Set perms) throws IOExcept e.type = Entry.COPY; // copy e } if (perms == null) { - e.posixPerms = -1; - } else if (e.posixPerms == -1) { - e.posixPerms = ZipUtils.permsToFlags(perms); + e.externalFileAttributes = -1; + } else if (e.externalFileAttributes == -1) { + e.externalFileAttributes = ZipUtils.permsToFlags(perms); } else { - e.posixPerms = ZipUtils.permsToFlags(perms) | - (e.posixPerms & 0xFE00); // Preserve unrelated bits + e.externalFileAttributes = ZipUtils.permsToFlags(perms) | + (e.externalFileAttributes & 0xFE00); // Preserve unrelated bits } update(e); } finally { @@ -2887,7 +2887,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { // entry attributes int version; int flag; - int posixPerms = -1; // posix permissions + int externalFileAttributes = -1; // file type, setuid, setgid, sticky, posix permissions int method = -1; // compression method long mtime = -1; // last modification time (in DOS time) long atime = -1; // last access time @@ -2923,7 +2923,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { for (FileAttribute attr : attrs) { String attrName = attr.name(); if (attrName.equals("posix:permissions")) { - posixPerms = ZipUtils.permsToFlags((Set)attr.value()); + externalFileAttributes = ZipUtils.permsToFlags((Set)attr.value()); } } } @@ -2958,7 +2958,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { */ this.locoff = e.locoff; this.comment = e.comment; - this.posixPerms = e.posixPerms; + this.externalFileAttributes = e.externalFileAttributes; this.type = type; } @@ -2988,7 +2988,7 @@ else if (method == METHOD_STORED) * to a version value. */ private int versionMadeBy(int version) { - return (posixPerms < 0) ? version : + return (externalFileAttributes < 0) ? version : VERSION_MADE_BY_BASE_UNIX | (version & 0xff); } @@ -3015,7 +3015,7 @@ private void readCEN(ZipFileSystem zipfs, IndexNode inode) throws IOException { attrsEx = CENATX(cen, pos); */ if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) { - posixPerms = (CENATX_PERMS(cen, pos) & 0xFFFF); // 16 bits for file type, setuid, setgid, sticky + perms + externalFileAttributes = (CENATX_PERMS(cen, pos) & 0xFFFF); // 16 bits for file type, setuid, setgid, sticky + perms } locoff = CENOFF(cen, pos); pos += CENHDR; @@ -3105,7 +3105,7 @@ private int writeCEN(OutputStream os) throws IOException { } writeShort(os, 0); // starting disk number writeShort(os, 0); // internal file attributes (unused) - writeInt(os, posixPerms > 0 ? posixPerms << 16 : 0); // external file + writeInt(os, externalFileAttributes > 0 ? externalFileAttributes << 16 : 0); // external file // attributes, used for storing posix // permissions writeInt(os, locoff0); // relative offset of local header @@ -3528,10 +3528,10 @@ public byte[] comment() { @Override public Optional> storedPermissions() { Set perms = null; - if (posixPerms != -1) { + if (externalFileAttributes != -1) { perms = HashSet.newHashSet(PosixFilePermission.values().length); for (PosixFilePermission perm : PosixFilePermission.values()) { - if ((posixPerms & ZipUtils.permToFlag(perm)) != 0) { + if ((externalFileAttributes & ZipUtils.permToFlag(perm)) != 0) { perms.add(perm); } } diff --git a/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java b/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java index c96eeeeb74d..db9811d4ec3 100644 --- a/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java +++ b/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ public static void main(String[] args) throws Exception { Files.write(Path.of(ZIPFILENAME), ZIPBYTES); // check attributes before signing - verifyExtraAttrs(ZIPFILENAME); + verifyExternalFileAttributes(ZIPFILENAME); // generate key for signing SecurityTools.keytool( @@ -82,7 +82,7 @@ public static void main(String[] args) throws Exception { .shouldContain(WARNING_MSG); // recheck attributes after signing - verifyExtraAttrs(ZIPFILENAME); + verifyExternalFileAttributes(ZIPFILENAME); // verify zip file - expect warning SecurityTools.jarsigner( @@ -95,8 +95,8 @@ public static void main(String[] args) throws Exception { .shouldContain(WARNING_MSG); } - private static void verifyExtraAttrs(String zipFileName) throws IOException { - // the 16 bit extra attributes value should equal 0xa1ff - look for that pattern. + private static void verifyExternalFileAttributes(String zipFileName) throws IOException { + // the 16 bit 'external file attributes' value should equal 0xa1ff - look for that pattern. // Such values can be read from zip file via 'unzip -Z -l -v ' try (FileInputStream fis = new FileInputStream(ZIPFILENAME)) { byte[] b = fis.readAllBytes(); @@ -107,7 +107,7 @@ private static void verifyExtraAttrs(String zipFileName) throws IOException { return; } } - throw new RuntimeException("extra attribute value not detected"); + throw new RuntimeException("external file attribute value not detected"); } } From 0db9bc57de07f8f1d0bf657621cb1b8fd7b01211 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 05:03:56 +0000 Subject: [PATCH 63/85] 8335290: Rename ClassFile::transform to ClassFile::transformClass Reviewed-by: asotona --- .../share/classes/java/lang/Module.java | 6 +-- .../java/lang/classfile/ClassFile.java | 15 ++++---- .../lang/classfile/ClassFileTransform.java | 2 +- .../classfile/components/ClassRemapper.java | 2 +- .../snippet-files/PackageSnippets.java | 8 ++-- .../snippet-files/PackageSnippets.java | 6 +-- .../classfile/impl/ClassFileImpl.java | 2 +- .../internal/module/ModuleInfoExtender.java | 2 +- .../StripJavaDebugAttributesPlugin.java | 2 +- .../internal/plugins/VersionPropsPlugin.java | 2 +- .../execution/LocalExecutionControl.java | 2 +- .../records/BadCanonicalCtrTest.java | 6 +-- .../records/ProhibitedMethods.java | 4 +- .../records/SerialPersistentFieldsTest.java | 4 +- .../lang/ModuleTests/AnnotationsTest.java | 4 +- .../lang/instrument/asmlib/Instrumentor.java | 4 +- .../java/lang/invoke/8022701/BogoLoader.java | 4 +- .../accessProtectedSuper/BogoLoader.java | 4 +- test/jdk/jdk/classfile/AdaptCodeTest.java | 8 ++-- .../AdvancedTransformationsTest.java | 6 +-- test/jdk/jdk/classfile/BSMTest.java | 4 +- test/jdk/jdk/classfile/ClassBuildingTest.java | 4 +- .../jdk/classfile/ClassHierarchyInfoTest.java | 4 +- test/jdk/jdk/classfile/CorpusTest.java | 6 +-- .../DiscontinuedInstructionsTest.java | 10 ++--- test/jdk/jdk/classfile/LvtTest.java | 4 +- .../jdk/classfile/MassAdaptCopyCodeTest.java | 4 +- .../MassAdaptCopyPrimitiveMatchCodeTest.java | 4 +- test/jdk/jdk/classfile/OptionsTest.java | 6 +-- test/jdk/jdk/classfile/ShortJumpsFixTest.java | 18 ++++----- test/jdk/jdk/classfile/StackMapsTest.java | 4 +- .../jdk/classfile/TestRecordComponent.java | 8 ++-- test/jdk/jdk/classfile/TransformTests.java | 14 +++---- test/jdk/jdk/classfile/VerifierSelfTest.java | 4 +- .../examples/AnnotationsExamples.java | 12 +++--- .../classfile/examples/ExampleGallery.java | 38 +++++++++---------- .../ExperimentalTransformExamples.java | 4 +- .../classfile/examples/TransformExamples.java | 12 +++--- .../jdk/jdk/classfile/helpers/Transforms.java | 10 ++--- .../jdk/jfr/event/io/TestInstrumentation.java | 2 +- .../javaagent/TestEventInstrumentation.java | 2 +- .../separate/ClassToInterfaceConverter.java | 4 +- .../tools/javac/MethodParametersTest.java | 6 +-- .../classreader/8171132/BadConstantValue.java | 3 +- .../javac/classreader/BadMethodParameter.java | 3 +- .../javac/defaultMethods/BadClassfile.java | 4 +- .../javac/launcher/SourceLauncherTest.java | 2 +- .../tools/javac/modules/IncubatingTest.java | 4 +- .../tools/javac/modules/JavaBaseTest.java | 4 +- .../tools/javac/modules/OpenModulesTest.java | 4 +- .../createsymbols/CreateSymbolsTestImpl.java | 4 +- .../processing/model/element/TestOrigin.java | 4 +- .../tools/javap/UndefinedAccessFlagTest.java | 2 +- .../bench/jdk/classfile/AdHocAdapt.java | 4 +- .../jdk/classfile/ClassfileBenchmark.java | 8 ++-- .../bench/jdk/classfile/ParseOptions.java | 8 ++-- .../jdk/classfile/RebuildMethodBodies.java | 4 +- .../bench/jdk/classfile/Transforms.java | 10 ++--- 58 files changed, 171 insertions(+), 174 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index 82dae27efa0..d7a70818618 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -54,13 +54,9 @@ import java.util.stream.Stream; import java.lang.classfile.AccessFlags; import java.lang.classfile.Attribute; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassTransform; import java.lang.classfile.ClassFile; -import java.lang.classfile.attribute.ModuleAttribute; import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import jdk.internal.javac.PreviewFeature; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; @@ -1588,7 +1584,7 @@ private Class loadModuleInfoClass() { private Class loadModuleInfoClass(InputStream in) throws IOException { final String MODULE_INFO = "module-info"; var cc = ClassFile.of(ClassFile.ConstantPoolSharingOption.NEW_POOL); - byte[] bytes = cc.transform(cc.parse(in.readAllBytes()), (clb, cle) -> { + byte[] bytes = cc.transformClass(cc.parse(in.readAllBytes()), (clb, cle) -> { switch (cle) { case AccessFlags af -> clb.withFlags(AccessFlag.INTERFACE, AccessFlag.ABSTRACT, AccessFlag.SYNTHETIC); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index 1997ffb487c..08745f7e1ba 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -32,7 +32,6 @@ import java.util.function.Function; import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.UnknownAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; @@ -435,15 +434,15 @@ default void buildModuleTo(Path path, * This method behaves as if: * {@snippet lang=java : * this.build(model.thisClass(), ConstantPoolBuilder.of(model), - * b -> b.transform(model, transform)); + * clb -> clb.transform(model, transform)); * } * * @param model the class model to transform * @param transform the transform * @return the bytes of the new class */ - default byte[] transform(ClassModel model, ClassTransform transform) { - return transform(model, model.thisClass(), transform); + default byte[] transformClass(ClassModel model, ClassTransform transform) { + return transformClass(model, model.thisClass(), transform); } /** @@ -458,8 +457,8 @@ default byte[] transform(ClassModel model, ClassTransform transform) { * @param transform the transform * @return the bytes of the new class */ - default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransform transform) { - return transform(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); + default byte[] transformClass(ClassModel model, ClassDesc newClassName, ClassTransform transform) { + return transformClass(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); } /** @@ -473,7 +472,7 @@ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransfor * This method behaves as if: * {@snippet lang=java : * this.build(newClassName, ConstantPoolBuilder.of(model), - * b -> b.transform(model, transform)); + * clb -> clb.transform(model, transform)); * } * * @param model the class model to transform @@ -481,7 +480,7 @@ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransfor * @param transform the transform * @return the bytes of the new class */ - byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform); + byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform); /** * Verify a classfile. Any verification errors found will be returned. diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java index 677478ec650..f67da06a36d 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java @@ -33,7 +33,7 @@ /** * A transformation on streams of elements. Transforms are used during * transformation of classfile entities; a transform is provided to a method like - * {@link ClassFile#transform(ClassModel, ClassTransform)}, and the elements of the class, + * {@link ClassFile#transformClass(ClassModel, ClassTransform)}, and the elements of the class, * along with a builder, are presented to the transform. * *

The subtypes of {@linkplain diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java index c69806b18c4..d3ae180dde5 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java @@ -107,6 +107,6 @@ static ClassRemapper of(Function mapFunction) { * @return re-mapped class file bytes */ default byte[] remapClass(ClassFile context, ClassModel clm) { - return context.transform(clm, map(clm.thisClass().asSymbol()), this); + return context.transformClass(clm, map(clm.thisClass().asSymbol()), this); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java index f96be4e0cdf..b53e9213813 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java @@ -130,7 +130,7 @@ void allPackageRemap(ClassModel... allMyClasses) { void codeLocalsShifting(ClassModel classModel) { // @start region="codeLocalsShifting" - byte[] newBytes = ClassFile.of().transform( + byte[] newBytes = ClassFile.of().transformClass( classModel, (classBuilder, classElement) -> { if (classElement instanceof MethodModel method) @@ -145,7 +145,7 @@ void codeLocalsShifting(ClassModel classModel) { void codeRelabeling(ClassModel classModel) { // @start region="codeRelabeling" - byte[] newBytes = ClassFile.of().transform( + byte[] newBytes = ClassFile.of().transformClass( classModel, ClassTransform.transformingMethodBodies( CodeTransform.ofStateful(CodeRelabeler::of))); @@ -160,7 +160,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { @@ -191,7 +191,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat //inlined target locals must be shifted based on the actual instrumentor locals codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder - .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) + .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) .andThen(CodeRelabeler.of()) .andThen((innerBuilder, shiftedTargetCode) -> { //returns must be replaced with jump to the end of the inlined method diff --git a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java index 5073e108465..b80c1c83284 100644 --- a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java @@ -195,7 +195,7 @@ void stripDebugMethods2(byte[] bytes) { builder.with(element); }; var cc = ClassFile.of(); - byte[] newBytes = cc.transform(cc.parse(bytes), ct); + byte[] newBytes = cc.transformClass(cc.parse(bytes), ct); // @end } @@ -346,7 +346,7 @@ void fooToBarUnrolled(ClassModel classModel) { void codeRelabeling(ClassModel classModel) { // @start region="codeRelabeling" - byte[] newBytes = ClassFile.of().transform(classModel, + byte[] newBytes = ClassFile.of().transformClass(classModel, ClassTransform.transformingMethodBodies( CodeTransform.ofStateful(CodeRelabeler::of))); // @end @@ -360,7 +360,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index 8bffbd6de4f..e4408d6c7b2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -115,7 +115,7 @@ public byte[] build(ClassEntry thisClassEntry, } @Override - public byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform) { + public byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform) { ConstantPoolBuilder constantPool = constantPoolSharingOption() == ConstantPoolSharingOption.SHARED_POOL ? ConstantPoolBuilder.of(model) : ConstantPoolBuilder.of(); diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java index c9d3fd0adb6..6bc32d54a30 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -153,7 +153,7 @@ public byte[] toByteArray() throws IOException { var cc = ClassFile.of(); var cm = cc.parse(in.readAllBytes()); Version v = ModuleInfoExtender.this.version; - return cc.transform(cm, ClassTransform.endHandler(clb -> { + return cc.transformClass(cm, ClassTransform.endHandler(clb -> { // ModuleMainClass attribute if (mainClass != null) { clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mainClass))); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java index 536c5100cd8..bbf2bfacd00 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java @@ -67,7 +67,7 @@ public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { var clm = newClassReader(path, resource, ClassFile.DebugElementsOption.DROP_DEBUG, ClassFile.LineNumbersOption.DROP_LINE_NUMBERS); - byte[] content = ClassFile.of().transform(clm, ClassTransform + byte[] content = ClassFile.of().transformClass(clm, ClassTransform .dropping(cle -> cle instanceof SourceFileAttribute || cle instanceof SourceDebugExtensionAttribute) .andThen(ClassTransform.transformingMethods(MethodTransform diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java index 973fa4d1268..f9a5463609a 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java @@ -101,7 +101,7 @@ public void configure(Map config) { @SuppressWarnings("deprecation") private byte[] redefine(String path, byte[] classFile) { - return ClassFile.of().transform(newClassReader(path, classFile), + return ClassFile.of().transformClass(newClassReader(path, classFile), ClassTransform.transformingMethodBodies( mm -> mm.methodName().equalsString(""), new CodeTransform() { diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java index a89c91d3667..3076c0fa76d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java @@ -89,7 +89,7 @@ public void load(ClassBytecodes[] cbcs) private static byte[] instrument(byte[] classFile) { var cc = ClassFile.of(); - return cc.transform(cc.parse(classFile), + return cc.transformClass(cc.parse(classFile), ClassTransform.transformingMethodBodies((cob, coe) -> { if (coe instanceof BranchInstruction) cob.invokestatic(CD_Cancel, "stopCheck", ConstantDescs.MTD_void); diff --git a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java index ca31213b28f..c9b757a7b51 100644 --- a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java +++ b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,7 @@ protected Class resolveClass(ObjectStreamClass desc) */ static byte[] removeConstructor(byte[] classBytes) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + return cf.transformClass(cf.parse(classBytes), ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME))); } @@ -217,7 +217,7 @@ static byte[] removeConstructor(byte[] classBytes) { */ static byte[] modifyConstructor(byte[] classBytes) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + return cf.transformClass(cf.parse(classBytes), ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) .andThen(ClassTransform.endHandler(clb -> clb.withMethodBody(INIT_NAME, MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC, cob -> { diff --git a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java index 53252aaf558..3a66e46f83b 100644 --- a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java +++ b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,7 +243,7 @@ static byte[] addReadObjectNoData(byte[] classBytes) { static byte[] addMethod(byte[] classBytes, String name, MethodTypeDesc desc) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.endHandler(clb -> { + return cf.transformClass(cf.parse(classBytes), ClassTransform.endHandler(clb -> { clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> { cob.loadConstant(name + " should not be invoked"); cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail", diff --git a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java index 4ff15aa84d4..12a5fe8c402 100644 --- a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,7 +231,7 @@ static byte[] addSerialPersistentFields(byte[] classBytes, ObjectStreamField[] spf) { var cf = ClassFile.of(); var model = cf.parse(classBytes); - return cf.transform(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf)); + return cf.transformClass(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf)); } /** A visitor that adds a serialPersistentFields field, and assigns it in clinit. */ diff --git a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java index 60487584273..1fffe710ce5 100644 --- a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java +++ b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public void testWithModuleInfoResourceXXXX() throws IOException { static byte[] addDeprecated(byte[] bytes, boolean forRemoval, String since) { var cf = ClassFile.of(); var oldModel = cf.parse(bytes); - return cf.transform(oldModel, new ClassTransform() { + return cf.transformClass(oldModel, new ClassTransform() { boolean rvaaFound = false; @Override diff --git a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java index 29f2740a874..77893ed8a11 100644 --- a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java +++ b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public void atEnd(ClassBuilder builder) { } public synchronized byte[] apply() { - var bytes = ClassFile.of().transform(model, transform); + var bytes = ClassFile.of().transformClass(model, transform); return dirty.get() ? bytes : null; } diff --git a/test/jdk/java/lang/invoke/8022701/BogoLoader.java b/test/jdk/java/lang/invoke/8022701/BogoLoader.java index ac06718b42a..e497c169c3a 100644 --- a/test/jdk/java/lang/invoke/8022701/BogoLoader.java +++ b/test/jdk/java/lang/invoke/8022701/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ protected Class loadClass(String name, boolean resolve) System.err.println("Replacing class " + name); } var cf = ClassFile.of(); - classData = cf.transform(cf.parse(classData), replaced.get(name)); + classData = cf.transformClass(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java index 0f149959928..9ed6422f015 100644 --- a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java +++ b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ protected Class loadClass(String name, boolean resolve) System.err.println("Replacing class " + name); } var cf = ClassFile.of(); - classData = cf.transform(cf.parse(classData), replaced.get(name)); + classData = cf.transformClass(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/jdk/classfile/AdaptCodeTest.java b/test/jdk/jdk/classfile/AdaptCodeTest.java index 2a75cd7e020..2b9dff58819 100644 --- a/test/jdk/jdk/classfile/AdaptCodeTest.java +++ b/test/jdk/jdk/classfile/AdaptCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ void testNullAdaptIterator() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(testClassPath); for (ClassTransform t : Transforms.noops) { - byte[] newBytes = cc.transform(cm, t); + byte[] newBytes = cc.transformClass(cm, t); String result = (String) new ByteArrayClassLoader(AdaptCodeTest.class.getClassLoader(), testClassName, newBytes) .getMethod(testClassName, "many") @@ -79,7 +79,7 @@ void testNullAdaptIterator2(String path) throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(fs.getPath(path)); for (ClassTransform t : Transforms.noops) { - byte[] newBytes = cc.transform(cm, t); + byte[] newBytes = cc.transformClass(cm, t); } } @@ -101,7 +101,7 @@ void testSevenOfThirteenIterator() throws Exception { } }); - byte[] newBytes = cc.transform(cm, transform); + byte[] newBytes = cc.transformClass(cm, transform); // Files.write(Path.of("foo.class"), newBytes); String result = (String) new ByteArrayClassLoader(AdaptCodeTest.class.getClassLoader(), testClassName, newBytes) diff --git a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java index 88792eedcf1..6c7194271a4 100644 --- a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java +++ b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java @@ -77,7 +77,7 @@ void testShiftLocals() throws Exception { try (var in = StackMapGenerator.class.getResourceAsStream("StackMapGenerator.class")) { var cc = ClassFile.of(); var clm = cc.parse(in.readAllBytes()); - cc.verify(cc.transform(clm, (clb, cle) -> { + cc.verify(cc.transformClass(clm, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel com) { @@ -303,7 +303,7 @@ private static byte[] instrument(ClassModel target, ClassModel instrumentor, Pre var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { @@ -334,7 +334,7 @@ private static byte[] instrument(ClassModel target, ClassModel instrumentor, Pre //inlined target locals must be shifted based on the actual instrumentor locals codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder - .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) + .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) .andThen(CodeRelabeler.of()) .andThen((innerBuilder, shiftedTargetCode) -> { //returns must be replaced with jump to the end of the inlined method diff --git a/test/jdk/jdk/classfile/BSMTest.java b/test/jdk/jdk/classfile/BSMTest.java index 927549f0210..d0cc87d7493 100644 --- a/test/jdk/jdk/classfile/BSMTest.java +++ b/test/jdk/jdk/classfile/BSMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ public class BSMTest { void testSevenOfThirteenIterator() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(testClassPath); - byte[] newBytes = cc.transform(cm, (cb, ce) -> { + byte[] newBytes = cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { diff --git a/test/jdk/jdk/classfile/ClassBuildingTest.java b/test/jdk/jdk/classfile/ClassBuildingTest.java index 83c794ae879..bf6380ae8fe 100644 --- a/test/jdk/jdk/classfile/ClassBuildingTest.java +++ b/test/jdk/jdk/classfile/ClassBuildingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public void test() throws Throwable { transform = transform.andThen(ClassTransform.transformingMethods(MethodTransform.dropping(me -> me instanceof SignatureAttribute))); - MethodHandles.lookup().defineClass(cc.transform(cm, transform)); + MethodHandles.lookup().defineClass(cc.transformClass(cm, transform)); } } diff --git a/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java b/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java index b8eadeda5e1..4065f1d5e2f 100644 --- a/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java +++ b/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,7 +122,7 @@ void transformAndVerify(ClassHierarchyResolver res) throws Exception { void transformAndVerifySingle(ClassHierarchyResolver res) throws Exception { Path path = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules/java.base/java/util/HashMap.class"); var classModel = ClassFile.of().parse(path); - byte[] newBytes = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(res)).transform(classModel, + byte[] newBytes = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(res)).transformClass(classModel, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index 64db67e6d8e..67a2ebabb31 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -79,7 +79,7 @@ class CorpusTest { static void splitTableAttributes(String sourceClassFile, String targetClassFile) throws IOException, URISyntaxException { var root = Paths.get(URI.create(CorpusTest.class.getResource("CorpusTest.class").toString())).getParent(); var cc = ClassFile.of(); - Files.write(root.resolve(targetClassFile), cc.transform(cc.parse(root.resolve(sourceClassFile)), ClassTransform.transformingMethodBodies((cob, coe) -> { + Files.write(root.resolve(targetClassFile), cc.transformClass(cc.parse(root.resolve(sourceClassFile)), ClassTransform.transformingMethodBodies((cob, coe) -> { var dcob = (DirectCodeBuilder)cob; var curPc = dcob.curPc(); switch (coe) { @@ -147,7 +147,7 @@ void testNullAdaptations(Path path) throws Exception { try { byte[] transformed = m.shared && m.classTransform != null ? ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS) - .transform(ClassFile.of().parse(bytes), m.classTransform) + .transformClass(ClassFile.of().parse(bytes), m.classTransform) : m.transform.apply(bytes); Map newDups = findDups(transformed); oldRecord = m.classRecord(bytes); @@ -210,7 +210,7 @@ void testNullAdaptations(Path path) throws Exception { //testing maxStack and maxLocals are calculated identically by StackMapGenerator and StackCounter byte[] noStackMaps = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS) - .transform(newModel, + .transformClass(newModel, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); var noStackModel = cc.parse(noStackMaps); var itStack = newModel.methods().iterator(); diff --git a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java index be7e425c694..9070f0b1d45 100644 --- a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java +++ b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void testJsrAndRetProcessing() throws Exception { .invoke(null, list); assertEquals(list, List.of("Hello", "World")); - bytes = cc.transform(cc.parse(bytes), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); + bytes = cc.transformClass(cc.parse(bytes), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); new ByteArrayClassLoader(DiscontinuedInstructionsTest.class.getClassLoader(), testClass, bytes) .getMethod(testClass, testMethod) @@ -84,17 +84,17 @@ void testJsrAndRetProcessing() throws Exception { var clm = cc.parse(bytes); //test failover stack map generation - cc.transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) + cc.transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(JAVA_6_VERSION, 0)))); //test failure of stack map generation for Java 7 assertThrows(IllegalArgumentException.class, () -> - cc.transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) + cc.transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(JAVA_7_VERSION, 0))))); //test failure of stack map generation when enforced to generate assertThrows(IllegalArgumentException.class, () -> ClassFile.of(ClassFile.StackMapsOption.GENERATE_STACK_MAPS) - .transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL))); + .transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL))); } } diff --git a/test/jdk/jdk/classfile/LvtTest.java b/test/jdk/jdk/classfile/LvtTest.java index 7c60d75823a..7fb289cc175 100644 --- a/test/jdk/jdk/classfile/LvtTest.java +++ b/test/jdk/jdk/classfile/LvtTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ void buildLVTEntries() throws Exception { ClassModel c = cc.parse(fileBytes); // Compare transformed model and original with CodeBuilder filter - byte[] newClass = cc.transform(c, Transforms.threeLevelNoop); + byte[] newClass = cc.transformClass(c, Transforms.threeLevelNoop); ClassRecord orig = ClassRecord.ofClassModel(cc.parse(fileBytes), ClassRecord.CompatibilityFilter.By_ClassBuilder); ClassRecord transformed = ClassRecord.ofClassModel(cc.parse(newClass), ClassRecord.CompatibilityFilter.By_ClassBuilder); ClassRecord.assertEqualsDeep(transformed, orig); diff --git a/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java index 423ea91802a..067bce8b75f 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ void copy(String name, byte[] bytes) throws Exception { } public byte[] adaptCopy(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { diff --git a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java index 0ac9de70472..67e20be0ad3 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,7 @@ void copy(String name, byte[] bytes) throws Exception { Map m2b = new HashMap<>(); Map m2c = new HashMap<>(); byte[] resultBytes = - cc.transform(cm, (cb, e) -> { + cc.transformClass(cm, (cb, e) -> { if (e instanceof MethodModel mm) { Optional code = mm.code(); if (code.isPresent()) { diff --git a/test/jdk/jdk/classfile/OptionsTest.java b/test/jdk/jdk/classfile/OptionsTest.java index eecc2d7a385..10e3855b060 100644 --- a/test/jdk/jdk/classfile/OptionsTest.java +++ b/test/jdk/jdk/classfile/OptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ static Path[] corpus() throws IOException, URISyntaxException { @MethodSource("corpus") void testAttributesProcessingOptionOnTransform(Path path) throws Exception { testNoUnstable(path, ClassFile.of().parse( - ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNSTABLE_ATRIBUTES).transform( + ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNSTABLE_ATRIBUTES).transformClass( ClassFile.of().parse(path), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)))); } @@ -108,7 +108,7 @@ void testUnknownAttribute() throws Exception { //test drop unknown at transform assertTrue(ClassFile.of().parse( - ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNKNOWN_ATTRIBUTES).transform( + ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNKNOWN_ATTRIBUTES).transformClass( ClassFile.of().parse(classBytes), ClassTransform.ACCEPT_ALL)).attributes().isEmpty()); } diff --git a/test/jdk/jdk/classfile/ShortJumpsFixTest.java b/test/jdk/jdk/classfile/ShortJumpsFixTest.java index a259795b551..63e9f0bf904 100644 --- a/test/jdk/jdk/classfile/ShortJumpsFixTest.java +++ b/test/jdk/jdk/classfile/ShortJumpsFixTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,7 +136,7 @@ void testFailBackJumpsDirectGen(Sample sample) throws Exception { @MethodSource("provideFwd") void testFixFwdJumpsTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -145,7 +145,7 @@ void testFixFwdJumpsTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFixBackJumpsTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -154,7 +154,7 @@ void testFixBackJumpsTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFailFwdJumpsTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -163,7 +163,7 @@ void testFailFwdJumpsTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFailBackJumpsTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -172,7 +172,7 @@ void testFailBackJumpsTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFixFwdJumpsChainedTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -181,7 +181,7 @@ void testFixFwdJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFixBackJumpsChainedTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -190,7 +190,7 @@ void testFixBackJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFailFwdJumpsChainedTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -199,7 +199,7 @@ void testFailFwdJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFailBackJumpsChainedTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index f72c237aa8f..137f5bac486 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -225,7 +225,7 @@ void testClassVersions() throws Exception { var actualVersion = cc.parse(StackMapsTest.class.getResourceAsStream("/testdata/Pattern1.class").readAllBytes()); //test transformation to class version 49 with removal of StackMapTable attributes - var version49 = cc.parse(cc.transform( + var version49 = cc.parse(cc.transformClass( actualVersion, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(49, 0))))); @@ -233,7 +233,7 @@ void testClassVersions() throws Exception { .walk().anyMatch(n -> n.name().equals("stack map frames"))); //test transformation to class version 50 with re-generation of StackMapTable attributes - assertEmpty(cc.verify(cc.transform( + assertEmpty(cc.verify(cc.transformClass( version49, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(50, 0)))))); diff --git a/test/jdk/jdk/classfile/TestRecordComponent.java b/test/jdk/jdk/classfile/TestRecordComponent.java index 95d56ffae8d..b39029154a0 100644 --- a/test/jdk/jdk/classfile/TestRecordComponent.java +++ b/test/jdk/jdk/classfile/TestRecordComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ void testAdapt() throws Exception { } else cb.with(ce); }; - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); ClassRecord.assertEquals(newModel, cm); } @@ -74,7 +74,7 @@ void testPassThrough() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(Files.readAllBytes(testClassPath)); ClassTransform xform = (cb, ce) -> cb.with(ce); - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); ClassRecord.assertEquals(newModel, cm); } @@ -92,7 +92,7 @@ void testChagne() throws Exception { else cb.with(ce); }; - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); RecordAttribute ra = newModel.findAttribute(Attributes.record()).orElseThrow(); assertEquals(ra.components().size(), 2, "Should have two components"); assertEquals(ra.components().get(0).name().stringValue(), "fooXYZ"); diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index 13abca0ec52..1df7b73bda5 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,8 +97,8 @@ void testSingleTransform() throws Exception { ClassModel cm = cc.parse(bytes); assertEquals(invoke(bytes), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2foo))), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar))), "bar"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo))), "foo"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar))), "bar"); } @Test @@ -110,7 +110,7 @@ void testSeq2() throws Exception { assertEquals(invoke(bytes), "foo"); ClassTransform transform = transformCode(foo2bar.andThen(bar2baz)); - assertEquals(invoke(cc.transform(cm, transform)), "baz"); + assertEquals(invoke(cc.transformClass(cm, transform)), "baz"); } @Test @@ -121,9 +121,9 @@ void testSeqN() throws Exception { ClassModel cm = cc.parse(bytes); assertEquals(invoke(bytes), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2foo)))), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2quux)))), "quux"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2foo)))), "foo"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2quux)))), "quux"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); } public static class TestClass { diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index ef1bc3cab30..529edbf2b79 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void testFailed() throws IOException { var cc = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of( className -> ClassHierarchyResolver.ClassHierarchyInfo.ofClass(null))); var classModel = cc.parse(path); - byte[] brokenClassBytes = cc.transform(classModel, + byte[] brokenClassBytes = cc.transformClass(classModel, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { diff --git a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java index 846645d93a9..a43ab72556e 100644 --- a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java +++ b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ public class AnnotationsExamples { public byte[] addAnno(ClassModel m) { // @@@ Not correct List annos = List.of(Annotation.of(ClassDesc.of("java.lang.FunctionalInterface"))); - return ClassFile.of().transform(m, ClassTransform.endHandler(cb -> cb.with(RuntimeVisibleAnnotationsAttribute.of(annos)))); + return ClassFile.of().transformClass(m, ClassTransform.endHandler(cb -> cb.with(RuntimeVisibleAnnotationsAttribute.of(annos)))); } /** @@ -75,7 +75,7 @@ public void swapAnnotation(ClassModel m) { var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) { - m2 = cc.parse(cc.transform(m, SWAP_ANNO_TRANSFORM)); + m2 = cc.parse(cc.transformClass(m, SWAP_ANNO_TRANSFORM)); } } } @@ -119,7 +119,7 @@ public void addAnnotation(ClassModel m) { var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) { - m2 = cc.parse(cc.transform(m, (cb, ce) -> { + m2 = cc.parse(cc.transformClass(m, (cb, ce) -> { if (ce instanceof RuntimeVisibleAnnotationsAttribute ra) { var oldAnnos = ra.annotations(); List newAnnos = new ArrayList<>(oldAnnos.size() + 1); @@ -145,7 +145,7 @@ public void addAnnotation(ClassModel m) { } public byte[] viaEndHandlerClassBuilderEdition(ClassModel m) { - return ClassFile.of().transform(m, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(m, ClassTransform.ofStateful(() -> new ClassTransform() { boolean found = false; @Override @@ -172,7 +172,7 @@ public void atEnd(ClassBuilder builder) { } public byte[] viaEndHandlerClassTransformEdition(ClassModel m) { - return ClassFile.of().transform(m, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(m, ClassTransform.ofStateful(() -> new ClassTransform() { boolean found = false; @Override diff --git a/test/jdk/jdk/classfile/examples/ExampleGallery.java b/test/jdk/jdk/classfile/examples/ExampleGallery.java index 736725eeebe..7de4a78ffbf 100644 --- a/test/jdk/jdk/classfile/examples/ExampleGallery.java +++ b/test/jdk/jdk/classfile/examples/ExampleGallery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ */ public class ExampleGallery { public byte[] changeClassVersion(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case ClassFileVersion cv -> cb.withVersion(57, 0); default -> cb.with(ce); @@ -71,7 +71,7 @@ public byte[] changeClassVersion(ClassModel cm) { } public byte[] incrementClassVersion(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case ClassFileVersion cv -> cb.withVersion(cv.majorVersion() + 1, 0); default -> cb.with(ce); @@ -80,7 +80,7 @@ public byte[] incrementClassVersion(ClassModel cm) { } public byte[] changeSuperclass(ClassModel cm, ClassDesc superclass) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case Superclass sc -> cb.withSuperclass(superclass); default -> cb.with(ce); @@ -89,11 +89,11 @@ public byte[] changeSuperclass(ClassModel cm, ClassDesc superclass) { } public byte[] overrideSuperclass(ClassModel cm, ClassDesc superclass) { - return ClassFile.of().transform(cm, ClassTransform.endHandler(cb -> cb.withSuperclass(superclass))); + return ClassFile.of().transformClass(cm, ClassTransform.endHandler(cb -> cb.withSuperclass(superclass))); } public byte[] removeInterface(ClassModel cm, String internalName) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case Interfaces i -> cb.withInterfaces(i.interfaces().stream() .filter(e -> !e.asInternalName().equals(internalName)) @@ -104,7 +104,7 @@ public byte[] removeInterface(ClassModel cm, String internalName) { } public byte[] addInterface(ClassModel cm, ClassDesc newIntf) { - return ClassFile.of().transform(cm, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(cm, ClassTransform.ofStateful(() -> new ClassTransform() { boolean seen = false; @Override @@ -133,7 +133,7 @@ public void atEnd(ClassBuilder builder) { } public byte[] addInterface1(ClassModel cm, ClassDesc newIntf) { - return ClassFile.of().transform(cm, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(cm, ClassTransform.ofStateful(() -> new ClassTransform() { Interfaces interfaces; @Override @@ -160,11 +160,11 @@ public void atEnd(ClassBuilder builder) { } public byte[] removeSignature(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute)); + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute)); } public byte[] changeSignature(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case SignatureAttribute sa -> { String result = sa.signature().stringValue(); @@ -176,7 +176,7 @@ public byte[] changeSignature(ClassModel cm) { } public byte[] setSignature(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute) + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute) .andThen(ClassTransform.endHandler(b -> b.with(SignatureAttribute.of( ClassSignature.of( ClassTypeSig.of(ClassDesc.of("impl.Fox"), @@ -187,16 +187,16 @@ public byte[] setSignature(ClassModel cm) { // @@@ strip annos (class, all) public byte[] stripFields(ClassModel cm, Predicate filter) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof FieldModel fm + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof FieldModel fm && filter.test(fm.fieldName().stringValue()))); } public byte[] addField(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.endHandler(cb -> cb.withField("cool", ClassDesc.ofDescriptor("(I)D"), ClassFile.ACC_PUBLIC))); + return ClassFile.of().transformClass(cm, ClassTransform.endHandler(cb -> cb.withField("cool", ClassDesc.ofDescriptor("(I)D"), ClassFile.ACC_PUBLIC))); } public byte[] changeFieldSig(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingFields((fb, fe) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingFields((fb, fe) -> { if (fe instanceof SignatureAttribute sa) fb.with(SignatureAttribute.of(Signature.parseFrom(sa.signature().stringValue().replace("this/", "that/")))); else @@ -205,7 +205,7 @@ public byte[] changeFieldSig(ClassModel cm) { } public byte[] changeFieldFlags(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingFields((fb, fe) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingFields((fb, fe) -> { switch (fe) { case AccessFlags a -> fb.with(AccessFlags.ofField(a.flagsMask() & ~ClassFile.ACC_PUBLIC & ~ClassFile.ACC_PROTECTED)); default -> fb.with(fe); @@ -214,7 +214,7 @@ public byte[] changeFieldFlags(ClassModel cm) { } public byte[] addException(ClassModel cm, ClassDesc ex) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethods( + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethods( MethodTransform.ofStateful(() -> new MethodTransform() { ExceptionsAttribute attr; @@ -258,11 +258,11 @@ public void accept(CodeBuilder codeB, CodeElement codeE) { } }); - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies(transform)); + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies(transform)); } public byte[] addInstrumentationBeforeInvoke(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { switch (codeE) { case InvokeInstruction i -> { codeB.nop(); @@ -274,7 +274,7 @@ public byte[] addInstrumentationBeforeInvoke(ClassModel cm) { } public byte[] replaceIntegerConstant(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { switch (codeE) { case ConstantInstruction ci -> { if (ci.constantValue() instanceof Integer i) codeB.loadConstant(i + 1); diff --git a/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java b/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java index d66cc6737da..c0bfceff16f 100644 --- a/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java +++ b/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public class ExperimentalTransformExamples { }; public byte[] deleteAnnotations(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case MethodModel m -> cb.transformMethod(m, dropMethodAnnos); case FieldModel f -> cb.transformField(f, dropFieldAnnos); diff --git a/test/jdk/jdk/classfile/examples/TransformExamples.java b/test/jdk/jdk/classfile/examples/TransformExamples.java index 97dfcd8a585..2473e024e70 100644 --- a/test/jdk/jdk/classfile/examples/TransformExamples.java +++ b/test/jdk/jdk/classfile/examples/TransformExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,18 +38,18 @@ */ public class TransformExamples { public byte[] noop(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.ACCEPT_ALL); + return ClassFile.of().transformClass(cm, ClassTransform.ACCEPT_ALL); } public byte[] deleteAllMethods(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof MethodModel)) b.with(e); }); } public byte[] deleteFieldsWithDollarInName(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof FieldModel fm && fm.fieldName().stringValue().contains("$"))) b.with(e); @@ -57,14 +57,14 @@ public byte[] deleteFieldsWithDollarInName(ClassModel cm) { } public byte[] deleteAttributes(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof Attribute)) b.with(e); }); } public byte[] keepMethodsAndFields(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (e instanceof MethodModel || e instanceof FieldModel) b.with(e); }); diff --git a/test/jdk/jdk/classfile/helpers/Transforms.java b/test/jdk/jdk/classfile/helpers/Transforms.java index 64b4836d50a..0b44c5a22aa 100644 --- a/test/jdk/jdk/classfile/helpers/Transforms.java +++ b/test/jdk/jdk/classfile/helpers/Transforms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,7 +187,7 @@ public enum NoOpTransform { shared ? options : Stream.concat(Stream.of(options), Stream.of(ClassFile.ConstantPoolSharingOption.NEW_POOL)).toArray(ClassFile.Option[]::new)); - this.transform = bytes -> cc.transform(cc.parse(bytes), classTransform); + this.transform = bytes -> cc.transformClass(cc.parse(bytes), classTransform); } public Optional classRecord(byte[] bytes) throws IOException { @@ -212,7 +212,7 @@ public enum InjectNopTransform { NOP_SHARED(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (cb, ce) -> { + return cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { @@ -253,7 +253,7 @@ public enum SimpleTransform { HIGH_SHARED_ADD_FIELD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, new ClassTransform() { + return cc.transformClass(cm, new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { builder.with(element); @@ -291,7 +291,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str HIGH_SHARED_DEL_METHOD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (builder, element) -> { + return cc.transformClass(cm, (builder, element) -> { if (!(element instanceof MethodModel mm)) builder.with(element); }); diff --git a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java index 5f3885f31bf..daa3d0162d4 100644 --- a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java +++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java @@ -317,7 +317,7 @@ public byte[] transform( instrClassesDone.add(target); var cf = ClassFile.of(); - return cf.transform(cf.parse(bytes), (clb, ce) -> { + return cf.transformClass(cf.parse(bytes), (clb, ce) -> { MethodKey key; if (ce instanceof MethodModel mm && instrMethodKeys.contains(key = new MethodKey( target, mm.methodName().stringValue(), mm.methodTypeSymbol()))) { diff --git a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java index 8a8415dc524..049a1172d0c 100644 --- a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java +++ b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java @@ -116,7 +116,7 @@ public byte[] transform(ClassLoader classLoader, String className, } var cf = ClassFile.of(); - result = cf.transform(cf.parse(bytes), (clb, ce) -> { + result = cf.transformClass(cf.parse(bytes), (clb, ce) -> { if (ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) { clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() { @Override diff --git a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java index 26c17901281..7bf9b19390e 100644 --- a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java +++ b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ private byte[] convertToInterface(ClassModel classModel) { } }; - return ClassFile.of().transform(classModel, + return ClassFile.of().transformClass(classModel, ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) .andThen(ClassTransform.transformingMethodBodies(ct)) .andThen(ClassTransform.endHandler(b -> b.withFlags(ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC))) diff --git a/test/langtools/tools/javac/MethodParametersTest.java b/test/langtools/tools/javac/MethodParametersTest.java index 8ce73671d1f..a4d55525e60 100644 --- a/test/langtools/tools/javac/MethodParametersTest.java +++ b/test/langtools/tools/javac/MethodParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ void modifyBaz(boolean flip) throws Exception { // Alter the MethodParameters attribute, changing the name of // the parameter from i to baz. - byte[] bazBytes = ClassFile.of().transform(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { + byte[] bazBytes = ClassFile.of().transformClass(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { if (methodElement instanceof MethodParametersAttribute a) { List newParameterInfos = new ArrayList<>(); for (MethodParameterInfo info : a.parameters()) { @@ -200,7 +200,7 @@ void modifyBaz(boolean flip) throws Exception { // Flip the code and method attributes(). This is for checking // that order doesn't matter. if (flip) { - bazBytes = ClassFile.of().transform(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { + bazBytes = ClassFile.of().transformClass(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { if (methodElement instanceof MethodParametersAttribute) { methodBuilder.with(cattr); } else if (methodElement instanceof CodeAttribute){ diff --git a/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java b/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java index b4230c461c1..a44adbf6d9e 100644 --- a/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java +++ b/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java @@ -1,5 +1,6 @@ /* * Copyright 2016 Google, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +185,7 @@ private static void swapConstantValues(File file) throws Exception { ClassModel cf = ClassFile.of().parse(file.toPath()); FieldModel a = cf.fields().getFirst(); FieldModel b = cf.fields().get(1); - byte[] Bytes = ClassFile.of().transform(cf, ClassTransform + byte[] Bytes = ClassFile.of().transformClass(cf, ClassTransform .dropping(ce -> ce instanceof ClassFileVersion || ce instanceof FieldModel) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder .withField(b.fieldName(), b.fieldType(), fieldBuilder -> { diff --git a/test/langtools/tools/javac/classreader/BadMethodParameter.java b/test/langtools/tools/javac/classreader/BadMethodParameter.java index b37a196e2ed..cddd3f24956 100644 --- a/test/langtools/tools/javac/classreader/BadMethodParameter.java +++ b/test/langtools/tools/javac/classreader/BadMethodParameter.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Alphabet LLC. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +149,7 @@ private static void transform(Path path) throws IOException { }; ClassTransform classTransform = ClassTransform.transformingMethods(methodTransform); - bytes = cf.transform(classModel, classTransform); + bytes = cf.transformClass(classModel, classTransform); Files.write(path, bytes); } } diff --git a/test/langtools/tools/javac/defaultMethods/BadClassfile.java b/test/langtools/tools/javac/defaultMethods/BadClassfile.java index 366692f17e3..589b65bcf66 100644 --- a/test/langtools/tools/javac/defaultMethods/BadClassfile.java +++ b/test/langtools/tools/javac/defaultMethods/BadClassfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ public static void main(String... args) throws Exception { private static void test(String classname, String expected) throws Exception { File classfile = new File(System.getProperty("test.classes", "."), classname + ".class"); ClassModel cf = ClassFile.of().parse(classfile.toPath()); - ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof ClassFileVersion) + ClassFile.of().transformClass(cf, ClassTransform.dropping(ce -> ce instanceof ClassFileVersion) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.withVersion(Target.JDK1_7.majorVersion, Target.JDK1_7.minorVersion)))); JavaCompiler c = ToolProvider.getSystemJavaCompiler(); JavacTaskImpl task = (JavacTaskImpl) c.getTask(null, null, null, Arrays.asList("-classpath", System.getProperty("test.classes", ".")), null, null); diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 5f558d421ff..5e70e84482d 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -743,7 +743,7 @@ public void testNoDuplicateIncubatorWarning(Path base) throws Exception { private static void markModuleAsIncubator(Path moduleInfoFile) throws Exception { ClassModel cf = ClassFile.of().parse(moduleInfoFile); ModuleResolutionAttribute newAttr = ModuleResolutionAttribute.of(WARN_INCUBATING); - byte[] newBytes = ClassFile.of().transform(cf, + byte[] newBytes = ClassFile.of().transformClass(cf, ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr))); try (OutputStream out = Files.newOutputStream(moduleInfoFile)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/IncubatingTest.java b/test/langtools/tools/javac/modules/IncubatingTest.java index 776023db5e5..ce9d372a2f6 100644 --- a/test/langtools/tools/javac/modules/IncubatingTest.java +++ b/test/langtools/tools/javac/modules/IncubatingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,7 +266,7 @@ private void copyJavaBase(Path targetDir) throws IOException { private void addModuleResolutionAttribute(Path classfile, int resolution_flags) throws Exception { ClassModel cm = ClassFile.of().parse(classfile); ModuleResolutionAttribute modRAttr = ModuleResolutionAttribute.of(resolution_flags); - byte[] newBytes = ClassFile.of().transform(cm, ClassTransform.dropping(ce -> ce instanceof ModuleResolutionAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm, ClassTransform.dropping(ce -> ce instanceof ModuleResolutionAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(modRAttr)))); try (OutputStream out = Files.newOutputStream(classfile)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/JavaBaseTest.java b/test/langtools/tools/javac/modules/JavaBaseTest.java index 188bc4801e5..6d9f574705d 100644 --- a/test/langtools/tools/javac/modules/JavaBaseTest.java +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,7 @@ void createClass(Path base, List mods, String target) throws Exception { modAttr1.provides()); Path modInfo = base.resolve("test-modules").resolve("module-info.class"); Files.createDirectories(modInfo.getParent()); - byte[] newBytes = ClassFile.of().transform(cm1, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm1, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(modAttr2)))); try (OutputStream out = Files.newOutputStream(modInfo)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/OpenModulesTest.java b/test/langtools/tools/javac/modules/OpenModulesTest.java index e21601031e7..f2bf1d00cc7 100644 --- a/test/langtools/tools/javac/modules/OpenModulesTest.java +++ b/test/langtools/tools/javac/modules/OpenModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,7 +243,7 @@ public void testNonZeroOpensInOpen(Path base) throws Exception { module.uses(), module.provides()); - byte[] newBytes = ClassFile.of().transform(cm, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newModule)))); try (OutputStream out = Files.newOutputStream(miClass)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java index 3a4fd85e54e..c66cd08852a 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java @@ -1070,7 +1070,7 @@ void testModuleMainClass() throws Exception { try { Path moduleInfo = classesDir.resolve("module-info.class"); byte[] newClassData = - cf.transform(cf.parse(moduleInfo), + cf.transformClass(cf.parse(moduleInfo), (builder, element) -> { builder.with(element); if (element instanceof ModuleAttribute) { @@ -1179,7 +1179,7 @@ void compileAndPack(Path output, Path outputFile, } ClassFile cf = ClassFile.of(); ClassModel cm = cf.parse(moduleInfo); - byte[] newData = cf.transform(cm, (builder, element) -> { + byte[] newData = cf.transformClass(cm, (builder, element) -> { builder.with(element); if (element instanceof ModuleAttribute) { builder.with(ModulePackagesAttribute.ofNames(packages.stream() diff --git a/test/langtools/tools/javac/processing/model/element/TestOrigin.java b/test/langtools/tools/javac/processing/model/element/TestOrigin.java index 1fae5374bea..dee13cbbeb2 100644 --- a/test/langtools/tools/javac/processing/model/element/TestOrigin.java +++ b/test/langtools/tools/javac/processing/model/element/TestOrigin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -302,7 +302,7 @@ public void testModuleDirectives(Path base) throws Exception { newOpens, module.uses(), module.provides()); - byte[] newClassFileBytes = ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute) + byte[] newClassFileBytes = ClassFile.of().transformClass(cf, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newModule)))); try (OutputStream out = Files.newOutputStream(moduleInfo)) { out.write(newClassFileBytes); diff --git a/test/langtools/tools/javap/UndefinedAccessFlagTest.java b/test/langtools/tools/javap/UndefinedAccessFlagTest.java index bb531fa369c..822c9e20f35 100644 --- a/test/langtools/tools/javap/UndefinedAccessFlagTest.java +++ b/test/langtools/tools/javap/UndefinedAccessFlagTest.java @@ -70,7 +70,7 @@ void test(TestLocation location) throws Throwable { )) { cm = cf.parse(is.readAllBytes()); } - var bytes = cf.transform(cm, (cb, ce) -> { + var bytes = cf.transformClass(cm, (cb, ce) -> { switch (ce) { case AccessFlags flags when location == TestLocation.CLASS -> cb .withFlags(flags.flagsMask() | ACC_PRIVATE); diff --git a/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java b/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java index 99ef450851e..c74956755b0 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,6 @@ public enum X { public void transform(Blackhole bh) { var cc = ClassFile.of(); for (byte[] bytes : classes) - bh.consume(cc.transform(cc.parse(bytes), transform.transform)); + bh.consume(cc.transformClass(cc.parse(bytes), transform.transform)); } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java index 05dd4b17583..c07eff075c9 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,18 +99,18 @@ private static void consume(CompoundElement parent) { @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithSharedCP(Blackhole bh) { - bh.consume(sharedCP.transform(benchModel, threeLevelNoop)); + bh.consume(sharedCP.transformClass(benchModel, threeLevelNoop)); } @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithNewCP(Blackhole bh) { - bh.consume(newCP.transform(benchModel, threeLevelNoop)); + bh.consume(newCP.transformClass(benchModel, threeLevelNoop)); } @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithAddedNOP(Blackhole bh) { - bh.consume(sharedCP.transform(benchModel, addNOP)); + bh.consume(sharedCP.transformClass(benchModel, addNOP)); } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java b/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java index ed5e0f150ac..29c555c4a60 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public void transformNoDebug(Blackhole bh) { var cc = ClassFile.of(ClassFile.DebugElementsOption.DROP_DEBUG); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } @@ -52,7 +52,7 @@ public void transformNoStackmap(Blackhole bh) { var cc = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } @@ -62,7 +62,7 @@ public void transformNoLineNumbers(Blackhole bh) { var cc = ClassFile.of(ClassFile.LineNumbersOption.DROP_LINE_NUMBERS); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java index d5e77c1a2a7..07deec0ae48 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ public void unshared() { } private static void transform(ClassFile cc, ClassModel clm) { - cc.transform(clm, ClassTransform.transformingMethodBodies((cob, coe) -> { + cc.transformClass(clm, ClassTransform.transformingMethodBodies((cob, coe) -> { switch (coe) { case FieldInstruction i -> cob.fieldAccess(i.opcode(), i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java b/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java index def55b5f20c..d49897dc9c2 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ public enum NoOpTransform { shared ? options : Stream.concat(Stream.of(options), Stream.of(ClassFile.ConstantPoolSharingOption.NEW_POOL)).toArray(ClassFile.Option[]::new)); - this.transform = bytes -> cc.transform(cc.parse(bytes), classTransform); + this.transform = bytes -> cc.transformClass(cc.parse(bytes), classTransform); } } @@ -198,7 +198,7 @@ public enum InjectNopTransform { NOP_SHARED(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (cb, ce) -> { + return cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { @@ -239,7 +239,7 @@ public enum SimpleTransform { HIGH_SHARED_ADD_FIELD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, new ClassTransform() { + return cc.transformClass(cm, new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { builder.with(element); @@ -277,7 +277,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str HIGH_SHARED_DEL_METHOD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (builder, element) -> { + return cc.transformClass(cm, (builder, element) -> { if (!(element instanceof MethodModel mm)) builder.with(element); }); From 7bc8f9c150cbf457edf6144adba734ecd5ca5a0f Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 05:55:28 +0000 Subject: [PATCH 64/85] 8335589: Fix -Wzero-as-null-pointer-constant warnings in IdealLoopTree ctor Reviewed-by: thartmann --- src/hotspot/share/opto/loopnode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 79faf9c931d..448c29b6976 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -607,7 +607,7 @@ class IdealLoopTree : public ResourceObj { bool _allow_optimizations; // Allow loop optimizations IdealLoopTree( PhaseIdealLoop* phase, Node *head, Node *tail ) - : _parent(0), _next(0), _child(0), + : _parent(nullptr), _next(nullptr), _child(nullptr), _head(head), _tail(tail), _phase(phase), _local_loop_unroll_limit(0), _local_loop_unroll_factor(0), From f3f90dc11a5cbc146a5ef8a73eadf4168373838d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 05:57:49 +0000 Subject: [PATCH 65/85] 8335592: Fix -Wzero-as-null-pointer-constant warnings in RootNode ctor Reviewed-by: thartmann --- src/hotspot/share/opto/rootnode.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/rootnode.hpp b/src/hotspot/share/opto/rootnode.hpp index 40e812023c1..3838578b4db 100644 --- a/src/hotspot/share/opto/rootnode.hpp +++ b/src/hotspot/share/opto/rootnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ // procedure start. class RootNode : public LoopNode { public: - RootNode( ) : LoopNode(0,0) { + RootNode( ) : LoopNode(nullptr, nullptr) { init_class_id(Class_Root); del_req(2); del_req(1); From 77a7078b82fd0cb3cfa13685072f04fdef33758b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 06:00:20 +0000 Subject: [PATCH 66/85] 8335593: Fix -Wzero-as-null-pointer-constant warning in Type_Array ctor Reviewed-by: thartmann --- src/hotspot/share/opto/phaseX.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 0025f4dca46..7843bd39aea 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ class Type_Array : public AnyObj { const Type **_types; void grow( uint i ); // Grow array node to fit public: - Type_Array(Arena *a) : _a(a), _max(0), _types(0) {} + Type_Array(Arena *a) : _a(a), _max(0), _types(nullptr) {} const Type *operator[] ( uint i ) const // Lookup, or null for not mapped { return (i<_max) ? _types[i] : (Type*)nullptr; } const Type *fast_lookup(uint i) const{assert(i<_max,"oob");return _types[i];} From 4d2f73764bcd5ff62fbdb9d406d4180ae09613ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Wed, 3 Jul 2024 08:08:22 +0000 Subject: [PATCH 67/85] 8335357: Delete HotSpotJDKReflection.oopSizeOffset Reviewed-by: dnsimon --- .../classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java index 21c6fb3dc0e..6ee925cd3a7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,9 +108,6 @@ boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) { return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed(); } - // This field is being kept around for compatibility with libgraal - @SuppressWarnings("unused") private long oopSizeOffset; - @Override ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { java.lang.reflect.Parameter[] javaParameters = getMethod(javaMethod).getParameters(); From 6c84e9c8cb71aac103901c0d92fe6ae51aabff15 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 08:42:43 +0000 Subject: [PATCH 68/85] 8335544: Serial: Remove unused _should_allocate_from_space Reviewed-by: iwalulya --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 1 - src/hotspot/share/gc/serial/defNewGeneration.hpp | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 593977030cb..7729ea71f02 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -229,7 +229,6 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, _promotion_failed(false), _preserved_marks_set(false /* in_c_heap */), _promo_failure_drain_in_progress(false), - _should_allocate_from_space(false), _string_dedup_requests() { MemRegion cmr((HeapWord*)_virtual_space.low(), diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 0cf2545421f..d0af3114b30 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -119,18 +119,6 @@ class DefNewGeneration: public Generation { size_t _max_eden_size; size_t _max_survivor_size; - // Allocation support - bool _should_allocate_from_space; - bool should_allocate_from_space() const { - return _should_allocate_from_space; - } - void clear_should_allocate_from_space() { - _should_allocate_from_space = false; - } - void set_should_allocate_from_space() { - _should_allocate_from_space = true; - } - // Tenuring void adjust_desired_tenuring_threshold(); From c06b75ff88babf57bdcd0919ea177ff363fd858b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 11:12:08 +0000 Subject: [PATCH 69/85] 8335591: Fix -Wzero-as-null-pointer-constant warnings in ConcurrentHashTable Reviewed-by: chagedorn --- .../share/utilities/concurrentHashTable.inline.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index a83b6dd8a58..78c7e148bbb 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -318,7 +318,7 @@ inline bool ConcurrentHashTable:: } else { return false; } - _invisible_epoch = 0; + _invisible_epoch = nullptr; _resize_lock_owner = locker; return true; } @@ -345,14 +345,14 @@ inline void ConcurrentHashTable:: } } while(true); _resize_lock_owner = locker; - _invisible_epoch = 0; + _invisible_epoch = nullptr; } template inline void ConcurrentHashTable:: unlock_resize_lock(Thread* locker) { - _invisible_epoch = 0; + _invisible_epoch = nullptr; assert(locker == _resize_lock_owner, "Not unlocked by locker."); _resize_lock_owner = nullptr; _resize_lock->unlock(); @@ -1016,7 +1016,7 @@ ConcurrentHashTable(size_t log2size, size_t log2size_limit, size_t grow_hint, bo : _context(context), _new_table(nullptr), _log2_size_limit(log2size_limit), _log2_start_size(log2size), _grow_hint(grow_hint), _size_limit_reached(false), _resize_lock_owner(nullptr), - _invisible_epoch(0) + _invisible_epoch(nullptr) { if (enable_statistics) { _stats_rate = new TableRateStatistics(); From 350f9c1947b0eab3ee233516ceefca1e25de9583 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 3 Jul 2024 11:36:14 +0000 Subject: [PATCH 70/85] 8322812: Manpage for jcmd is missing JFR.view command Reviewed-by: kevinw, mgronlun --- src/jdk.jcmd/share/man/jcmd.1 | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index 2befaf5a949..1a8aefde06e 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -681,6 +681,55 @@ If no path is provided, the data from the recording is discarded. value) .RE .TP +\f[V]JFR.view\f[R] [\f[I]options\f[R]] +Display event data in predefined views. +.RS +.PP +Impact: Medium +.PP +\f[B]Note:\f[R] +.PP +The \f[I]options\f[R] must be specified using either \f[I]key\f[R] or +\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +If no parameters are entered, then a list of available views are +displayed. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]cell-height\f[R]: (Optional) Maximum number of rows in a table +cell. +(INT, default value depends on the view) +.IP \[bu] 2 +\f[V]maxage\f[R]: (Optional) Length of time for the view to span. +(INT followed by \[aq]s\[aq] for seconds \[aq]m\[aq] for minutes or +\[aq]h\[aq] for hours, default value is 10m) +.IP \[bu] 2 +\f[V]maxsize\f[R]: (Optional) Maximum size for the view to span in bytes +if one of the following suffixes is not used: \[aq]m\[aq] or \[aq]M\[aq] +for megabytes OR \[aq]g\[aq] or \[aq]G\[aq] for gigabytes. +(STRING, default value is 32MB) +.IP \[bu] 2 +\f[V]truncate\f[R]: (Optional) Maximum number of rows in a table cell. +(INT, default value depends on the view) +.IP \[bu] 2 +\f[V]verbose\f[R]: (Optional) Displays the query that makes up the view. +(BOOLEAN, default value is false) +.IP \[bu] 2 +\f[V]width\f[R]: (Optional) The width of the view in characters. +(INT, default value depends on the view) +.PP +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[V]view\f[R]: Name of the view or event type to display. +Use \f[V]help JFR.view\f[R] to see a list of available views. +(STRING, no default value) +.PP +The view parameter can be an event type name. +Use \f[V]JFR.view types\f[R] to see a list. +To display all views, use \f[V]JFR.view all-views\f[R]. +To display all events, use \f[V]JFR.view all-events\f[R]. +.RE +.TP \f[V]JVMTI.agent_load\f[R] [\f[I]arguments\f[R]] Loads JVMTI native agent. .RS From 6db4c6a772df856fc3099c32a5b2c102a30d360c Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Wed, 3 Jul 2024 12:12:00 +0000 Subject: [PATCH 71/85] 8335536: Fix assertion failure in IdealGraphPrinter when append is true Reviewed-by: thartmann, chagedorn, tholenstein --- src/hotspot/share/opto/idealGraphPrinter.cpp | 30 +++++++++++++------- src/hotspot/share/opto/idealGraphPrinter.hpp | 3 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 8a9da980893..4b813252ff9 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -143,21 +143,24 @@ void IdealGraphPrinter::init(const char* file_name, bool use_multiple_files, boo _depth = 0; _current_method = nullptr; _network_stream = nullptr; + _append = append; if (file_name != nullptr) { - init_file_stream(file_name, use_multiple_files, append); + init_file_stream(file_name, use_multiple_files); } else { init_network_stream(); } _xml = new (mtCompiler) xmlStream(_output); - if (!append) { + if (!_append) { head(TOP_ELEMENT); } } // Destructor, close file or network stream IdealGraphPrinter::~IdealGraphPrinter() { - tail(TOP_ELEMENT); + if (!_append) { + tail(TOP_ELEMENT); + } // tty->print_cr("Walk time: %d", (int)_walk_time.milliseconds()); // tty->print_cr("Output time: %d", (int)_output_time.milliseconds()); @@ -860,10 +863,10 @@ void IdealGraphPrinter::print(const char *name, Node *node) { _xml->flush(); } -void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files, bool append) { +void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files) { ThreadCritical tc; if (use_multiple_files && _file_count != 0) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); ResourceMark rm; stringStream st; const char* dot = strrchr(file_name, '.'); @@ -875,10 +878,10 @@ void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multipl } _output = new (mtCompiler) fileStream(st.as_string(), "w"); } else { - _output = new (mtCompiler) fileStream(file_name, append ? "a" : "w"); + _output = new (mtCompiler) fileStream(file_name, _append ? "a" : "w"); } if (use_multiple_files) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); _file_count++; } } @@ -909,9 +912,16 @@ void IdealGraphPrinter::update_compiled_method(ciMethod* current_method) { assert(C != nullptr, "must already be set"); if (current_method != _current_method) { // If a different method, end the old and begin with the new one. - end_method(); - _current_method = nullptr; - begin_method(); + if (_append) { + // Do not call `end_method` if we are appending, just update `_current_method`, + // because `begin_method` is not called in the constructor in append mode. + _current_method = current_method; + } else { + // End the old method and begin a new one. + // Don't worry about `_current_method`, `end_method` will clear it. + end_method(); + begin_method(); + } } } diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 11b0b6e5ea1..65d7f4b5473 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -96,6 +96,7 @@ class IdealGraphPrinter : public CHeapObj { bool _traverse_outs; Compile *C; double _max_freq; + bool _append; void print_method(ciMethod* method, int bci, InlineTree* tree); void print_inline_tree(InlineTree* tree); @@ -118,7 +119,7 @@ class IdealGraphPrinter : public CHeapObj { void head(const char *name); void text(const char *s); void init(const char* file_name, bool use_multiple_files, bool append); - void init_file_stream(const char* file_name, bool use_multiple_files, bool append); + void init_file_stream(const char* file_name, bool use_multiple_files); void init_network_stream(); IdealGraphPrinter(); ~IdealGraphPrinter(); From 5866b16dbca3f63770c8792d204dabdf49b59839 Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Wed, 3 Jul 2024 12:12:12 +0000 Subject: [PATCH 72/85] 8335411: RISC-V: Optimize encode_heap_oop when oop is not null Reviewed-by: fyang, rehn --- .../cpu/riscv/macroAssembler_riscv.cpp | 47 ++++++++++++++++++- .../cpu/riscv/macroAssembler_riscv.hpp | 4 +- src/hotspot/cpu/riscv/riscv.ad | 14 +++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b707b20f669..a04c02bbc45 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2664,6 +2664,51 @@ void MacroAssembler::encode_heap_oop(Register d, Register s) { } } +void MacroAssembler::encode_heap_oop_not_null(Register r) { +#ifdef ASSERT + if (CheckCompressedOops) { + Label ok; + bnez(r, ok); + stop("null oop passed to encode_heap_oop_not_null"); + bind(ok); + } +#endif + verify_oop_msg(r, "broken oop in encode_heap_oop_not_null"); + if (CompressedOops::base() != nullptr) { + sub(r, r, xheapbase); + } + if (CompressedOops::shift() != 0) { + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(r, r, LogMinObjAlignmentInBytes); + } +} + +void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { +#ifdef ASSERT + if (CheckCompressedOops) { + Label ok; + bnez(src, ok); + stop("null oop passed to encode_heap_oop_not_null2"); + bind(ok); + } +#endif + verify_oop_msg(src, "broken oop in encode_heap_oop_not_null2"); + + Register data = src; + if (CompressedOops::base() != nullptr) { + sub(dst, src, xheapbase); + data = dst; + } + if (CompressedOops::shift() != 0) { + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(dst, data, LogMinObjAlignmentInBytes); + data = dst; + } + if (data == src) { + mv(dst, src); + } +} + void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { assert_different_registers(dst, tmp); assert_different_registers(src, tmp); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index ddd3c48a93e..ea2b9229eab 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1,7 +1,7 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,8 @@ class MacroAssembler: public Assembler { void decode_heap_oop_not_null(Register dst, Register src); void decode_heap_oop(Register d, Register s); void decode_heap_oop(Register r) { decode_heap_oop(r, r); } + void encode_heap_oop_not_null(Register r); + void encode_heap_oop_not_null(Register dst, Register src); void encode_heap_oop(Register d, Register s); void encode_heap_oop(Register r) { encode_heap_oop(r, r); }; void load_heap_oop(Register dst, Address src, Register tmp1, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 4ed449032d6..e2a1fcf621f 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1,7 +1,7 @@ // // Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. -// Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. +// Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -8404,6 +8404,7 @@ instruct round_float_reg(iRegINoSp dst, fRegF src, fRegF ftmp) %{ // Convert oop pointer into compressed form instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ + predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); match(Set dst (EncodeP src)); ins_cost(ALU_COST); format %{ "encode_heap_oop $dst, $src\t#@encodeHeapOop" %} @@ -8415,6 +8416,17 @@ instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ ins_pipe(pipe_class_default); %} +instruct encodeHeapOop_not_null(iRegNNoSp dst, iRegP src) %{ + predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); + match(Set dst (EncodeP src)); + ins_cost(ALU_COST); + format %{ "encode_heap_oop_not_null $dst, $src\t#@encodeHeapOop_not_null" %} + ins_encode %{ + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(pipe_class_default); +%} + instruct decodeHeapOop(iRegPNoSp dst, iRegN src) %{ predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); From 6923a5114b2a9f02f0d6f0fefc21141ac3b9322a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 12:57:26 +0000 Subject: [PATCH 73/85] 8335607: Serial: Remove unused collection_attempt_is_safe Reviewed-by: tschatzl --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 11 ----------- src/hotspot/share/gc/serial/defNewGeneration.hpp | 7 ------- 2 files changed, 18 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 7729ea71f02..acf7e239103 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -834,17 +834,6 @@ void DefNewGeneration::reset_scratch() { } } -bool DefNewGeneration::collection_attempt_is_safe() { - if (!to()->is_empty()) { - log_trace(gc)(":: to is not empty ::"); - return false; - } - if (_old_gen == nullptr) { - _old_gen = SerialHeap::heap()->old_gen(); - } - return _old_gen->promotion_attempt_is_safe(used()); -} - void DefNewGeneration::gc_epilogue(bool full) { assert(!GCLocker::is_active(), "We should not be executing here"); // update the generation and space performance counters diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index d0af3114b30..5c8dd08e40b 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -228,13 +228,6 @@ class DefNewGeneration: public Generation { // GC support void compute_new_size(); - // Returns true if the collection is likely to be safely - // completed. Even if this method returns true, a collection - // may not be guaranteed to succeed, and the system should be - // able to safely unwind and recover from that failure, albeit - // at some additional cost. - bool collection_attempt_is_safe(); - bool collect(bool clear_all_soft_refs); HeapWord* expand_and_allocate(size_t size, bool is_tlab); From 5a8af2b8b93672de9b3a3e73e6984506980da932 Mon Sep 17 00:00:00 2001 From: Arseny Bochkarev Date: Wed, 3 Jul 2024 14:09:59 +0000 Subject: [PATCH 74/85] 8335615: Clean up left-overs from 8317721 Reviewed-by: fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a04c02bbc45..b3ae5fbcdd0 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1494,10 +1494,9 @@ void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1, xorr(crc, crc, tmp2); lwu(tmp2, Address(tmp3)); - if (upper) { - tmp1 = v; + // It is more optimal to use 'srli' instead of 'srliw' for case when it is not necessary to clean upper bits + if (upper) srli(tmp1, v, 24); - } else srliw(tmp1, v, 24); From cf4f2b53d6174a808f8b45f0bb848efd5bd91c3c Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 3 Jul 2024 15:12:40 +0000 Subject: [PATCH 75/85] 8332517: G1: Refactor G1AllocRegion Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 46 +++++------ src/hotspot/share/gc/g1/g1AllocRegion.hpp | 56 +++++-------- .../share/gc/g1/g1AllocRegion.inline.hpp | 38 +++------ src/hotspot/share/gc/g1/g1Allocator.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 22 +++-- .../share/gc/g1/g1HeapRegion.inline.hpp | 82 ++++++++----------- 6 files changed, 99 insertions(+), 147 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index a205cf71ee6..c4ab81cda8f 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -100,16 +100,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up) // it will never be empty. size_t waste = 0; assert_alloc_region(!alloc_region->is_empty(), - "the alloc region should never be empty"); + "the alloc region should never be empty"); if (fill_up) { waste = fill_up_remaining_space(alloc_region); } - assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); - size_t allocated_bytes = alloc_region->used() - _used_bytes_before; - retire_region(alloc_region, allocated_bytes); - _used_bytes_before = 0; + retire_region(alloc_region); return waste; } @@ -132,15 +129,14 @@ size_t G1AllocRegion::retire(bool fill_up) { HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { assert_alloc_region(_alloc_region == _dummy_region, "pre-condition"); - assert_alloc_region(_used_bytes_before == 0, "pre-condition"); trace("attempting region allocation"); G1HeapRegion* new_alloc_region = allocate_new_region(word_size); if (new_alloc_region != nullptr) { new_alloc_region->reset_pre_dummy_top(); - // Need to do this before the allocation - _used_bytes_before = new_alloc_region->used(); - HeapWord* result = allocate(new_alloc_region, word_size); + + assert(new_alloc_region->is_empty(), "new regions should be empty"); + HeapWord* result = new_alloc_region->allocate(word_size); assert_alloc_region(result != nullptr, "the allocation should succeeded"); OrderAccess::storestore(); @@ -159,7 +155,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { void G1AllocRegion::init() { trace("initializing"); - assert_alloc_region(_alloc_region == nullptr && _used_bytes_before == 0, "pre-condition"); + assert_alloc_region(_alloc_region == nullptr, "pre-condition"); assert_alloc_region(_dummy_region != nullptr, "should have been set"); _alloc_region = _dummy_region; _count = 0; @@ -168,16 +164,9 @@ void G1AllocRegion::init() { void G1AllocRegion::set(G1HeapRegion* alloc_region) { trace("setting"); - // We explicitly check that the region is not empty to make sure we - // maintain the "the alloc region cannot be empty" invariant. - assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition"); - assert_alloc_region(_alloc_region == _dummy_region && - _used_bytes_before == 0 && _count == 0, - "pre-condition"); + assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition"); - _used_bytes_before = alloc_region->used(); - _alloc_region = alloc_region; - _count += 1; + update_alloc_region(alloc_region); trace("set"); } @@ -237,7 +226,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ if (detailed_info) { if (result != nullptr) { out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT " actual " SIZE_FORMAT " " PTR_FORMAT, - min_word_size, desired_word_size, actual_word_size, p2i(result)); + min_word_size, desired_word_size, actual_word_size, p2i(result)); } else if (min_word_size != 0) { out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT, min_word_size, desired_word_size); } @@ -252,7 +241,6 @@ G1AllocRegion::G1AllocRegion(const char* name, uint node_index) : _alloc_region(nullptr), _count(0), - _used_bytes_before(0), _name(name), _node_index(node_index) { } @@ -261,9 +249,8 @@ G1HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_mutator_alloc_region(word_size, _node_index); } -void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) { - _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes); +void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) { + _g1h->retire_mutator_alloc_region(alloc_region, alloc_region->used()); } void MutatorAllocRegion::init() { @@ -346,9 +333,11 @@ G1HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_gc_alloc_region(word_size, _purpose, _node_index); } -void G1GCAllocRegion::retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) { +void G1GCAllocRegion::retire_region(G1HeapRegion* alloc_region) { + assert(alloc_region->used() >= _used_bytes_before, "invariant"); + size_t allocated_bytes = alloc_region->used() - _used_bytes_before; _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, _purpose); + _used_bytes_before = 0; } size_t G1GCAllocRegion::retire(bool fill_up) { @@ -360,3 +349,8 @@ size_t G1GCAllocRegion::retire(bool fill_up) { } return end_waste; } + +void G1GCAllocRegion::reuse(G1HeapRegion* alloc_region) { + _used_bytes_before = alloc_region->used(); + set(alloc_region); +} diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index a8903fd54f1..391ded28388 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -63,11 +63,6 @@ class G1AllocRegion : public CHeapObj { // distinct regions this object can used during an active interval. uint _count; - // When we set up a new active region we save its used bytes in this - // field so that, when we retire it, we can calculate how much space - // we allocated in it. - size_t _used_bytes_before; - // Useful for debugging and tracing. const char* _name; @@ -94,24 +89,14 @@ class G1AllocRegion : public CHeapObj { // The memory node index this allocation region belongs to. uint _node_index; + void set(G1HeapRegion* alloc_region); + // Reset the alloc region to point the dummy region. void reset_alloc_region(); - // Perform a non-MT-safe allocation out of the given region. - inline HeapWord* allocate(G1HeapRegion* alloc_region, - size_t word_size); - // Perform a MT-safe allocation out of the given region. inline HeapWord* par_allocate(G1HeapRegion* alloc_region, size_t word_size); - // Perform a MT-safe allocation out of the given region, with the given - // minimum and desired size. Returns the actual size allocated (between - // minimum and desired size) in actual_word_size if the allocation has been - // successful. - inline HeapWord* par_allocate(G1HeapRegion* alloc_region, - size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size); // Ensure that the region passed as a parameter has been filled up // so that no one else can allocate out of it any more. @@ -131,8 +116,7 @@ class G1AllocRegion : public CHeapObj { static G1CollectedHeap* _g1h; virtual G1HeapRegion* allocate_new_region(size_t word_size) = 0; - virtual void retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) = 0; + virtual void retire_region(G1HeapRegion* alloc_region) = 0; G1AllocRegion(const char* name, bool bot_updates, uint node_index); @@ -173,12 +157,6 @@ class G1AllocRegion : public CHeapObj { // Should be called before we start using this object. virtual void init(); - // This can be used to set the active region to a specific - // region. (Use Example: we try to retain the last old GC alloc - // region that we've used during a GC and we can use set() to - // re-instate it at the beginning of the next GC.) - void set(G1HeapRegion* alloc_region); - // Should be called when we want to release the active region which // is returned after it's been retired. virtual G1HeapRegion* release(); @@ -205,10 +183,9 @@ class MutatorAllocRegion : public G1AllocRegion { // in it and the free size in the currently retained region, if any. bool should_retain(G1HeapRegion* region); protected: - virtual G1HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); - virtual size_t retire(bool fill_up); - + G1HeapRegion* allocate_new_region(size_t word_size) override; + void retire_region(G1HeapRegion* alloc_region) override; + size_t retire(bool fill_up) override; public: MutatorAllocRegion(uint node_index) : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */, node_index), @@ -231,27 +208,36 @@ class MutatorAllocRegion : public G1AllocRegion { // This specialization of release() makes sure that the retained alloc // region is retired and set to null. - virtual G1HeapRegion* release(); + G1HeapRegion* release() override; - virtual void init(); + void init() override; }; // Common base class for allocation regions used during GC. class G1GCAllocRegion : public G1AllocRegion { + // When we set up a new active region we save its used bytes in this + // field so that, when we retire it, we can calculate how much space + // we allocated in it. + size_t _used_bytes_before; protected: G1EvacStats* _stats; G1HeapRegionAttr::region_type_t _purpose; - virtual G1HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); + G1HeapRegion* allocate_new_region(size_t word_size) override; + void retire_region(G1HeapRegion* alloc_region) override; - virtual size_t retire(bool fill_up); + size_t retire(bool fill_up) override; G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, G1HeapRegionAttr::region_type_t purpose, uint node_index = G1NUMA::AnyNodeIndex) - : G1AllocRegion(name, bot_updates, node_index), _stats(stats), _purpose(purpose) { + : G1AllocRegion(name, bot_updates, node_index), _used_bytes_before(0), _stats(stats), _purpose(purpose) { assert(stats != nullptr, "Must pass non-null PLAB statistics"); } +public: + // This can be used to reuse a specific region. (Use Example: we try to retain the + // last old GC alloc region that we've used during a GC and we can use reuse() to + // re-instate it at the beginning of the next GC.) + void reuse(G1HeapRegion* alloc_region); }; class SurvivorGCAllocRegion : public G1GCAllocRegion { diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index ba4f1a12628..457a83f4285 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -31,9 +31,9 @@ #define assert_alloc_region(p, message) \ do { \ - assert((p), "[%s] %s c: %u r: " PTR_FORMAT " u: " SIZE_FORMAT, \ - _name, (message), _count, p2i(_alloc_region), \ - _used_bytes_before); \ + assert((p), "[%s] %s c: %u r: " PTR_FORMAT, \ + _name, (message), _count, p2i(_alloc_region) \ + ); \ } while (0) @@ -41,41 +41,27 @@ inline void G1AllocRegion::reset_alloc_region() { _alloc_region = _dummy_region; } -inline HeapWord* G1AllocRegion::allocate(G1HeapRegion* alloc_region, - size_t word_size) { - assert(alloc_region != nullptr, "pre-condition"); - - return alloc_region->allocate(word_size); -} - inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) { - size_t temp; - return par_allocate(alloc_region, word_size, word_size, &temp); -} - -inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, - size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { assert(alloc_region != nullptr, "pre-condition"); assert(!alloc_region->is_empty(), "pre-condition"); - - return alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); + size_t temp; + return alloc_region->par_allocate(word_size, word_size, &temp); } inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { G1HeapRegion* alloc_region = _alloc_region; - assert_alloc_region(alloc_region != nullptr, "not initialized properly"); + assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly"); + + HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); - HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size); if (result != nullptr) { trace("alloc", min_word_size, desired_word_size, *actual_word_size, result); - return result; + } else { + trace("alloc failed", min_word_size, desired_word_size); } - trace("alloc failed", min_word_size, desired_word_size); - return nullptr; + return result; } inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size) { @@ -112,7 +98,7 @@ inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word size_t desired_word_size, size_t* actual_word_size) { if (_retained_alloc_region != nullptr) { - HeapWord* result = par_allocate(_retained_alloc_region, min_word_size, desired_word_size, actual_word_size); + HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); if (result != nullptr) { trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result); return result; diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 05c64287ec0..29ce8e26bbb 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -118,7 +118,7 @@ void G1Allocator::reuse_retained_old_region(G1EvacInfo* evacuation_info, // we allocate to in the region sets. We'll re-add it later, when // it's retired again. _g1h->old_set_remove(retained_region); - old->set(retained_region); + old->reuse(retained_region); G1HeapRegionPrinter::reuse(retained_region); evacuation_info->set_alloc_regions_used_before(retained_region->used()); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index dc2c71bcbb4..67d6556203c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -127,18 +127,6 @@ class G1HeapRegion : public CHeapObj { void mangle_unused_area() PRODUCT_RETURN; - // Try to allocate at least min_word_size and up to desired_size from this region. - // Returns null if not possible, otherwise sets actual_word_size to the amount of - // space allocated. - // This version assumes that all allocation requests to this G1HeapRegion are properly - // synchronized. - inline HeapWord* allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); - // Try to allocate at least min_word_size and up to desired_size from this G1HeapRegion. - // Returns null if not possible, otherwise sets actual_word_size to the amount of - // space allocated. - // This version synchronizes with other calls to par_allocate_impl(). - inline HeapWord* par_allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); - inline HeapWord* advance_to_block_containing_addr(const void* addr, HeapWord* const pb, HeapWord* first_block) const; @@ -163,8 +151,18 @@ class G1HeapRegion : public CHeapObj { // All allocations are done without updating the BOT. The BOT // needs to be kept in sync for old generation regions and // this is done by explicit updates when crossing thresholds. + + // Try to allocate at least min_word_size and up to desired_size from this HeapRegion. + // Returns null if not possible, otherwise sets actual_word_size to the amount of + // space allocated. + // This version synchronizes with other calls to par_allocate(). inline HeapWord* par_allocate(size_t min_word_size, size_t desired_word_size, size_t* word_size); inline HeapWord* allocate(size_t word_size); + // Try to allocate at least min_word_size and up to desired_size from this region. + // Returns null if not possible, otherwise sets actual_word_size to the amount of + // space allocated. + // This version assumes that all allocation requests to this HeapRegion are properly + // synchronized. inline HeapWord* allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_size); // Full GC support methods. diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index 8e5e594b5ca..f31c5fb553e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -42,47 +42,6 @@ #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" -inline HeapWord* G1HeapRegion::allocate_impl(size_t min_word_size, - size_t desired_word_size, - size_t* actual_size) { - HeapWord* obj = top(); - size_t available = pointer_delta(end(), obj); - size_t want_to_allocate = MIN2(available, desired_word_size); - if (want_to_allocate >= min_word_size) { - HeapWord* new_top = obj + want_to_allocate; - set_top(new_top); - assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); - *actual_size = want_to_allocate; - return obj; - } else { - return nullptr; - } -} - -inline HeapWord* G1HeapRegion::par_allocate_impl(size_t min_word_size, - size_t desired_word_size, - size_t* actual_size) { - do { - HeapWord* obj = top(); - size_t available = pointer_delta(end(), obj); - size_t want_to_allocate = MIN2(available, desired_word_size); - if (want_to_allocate >= min_word_size) { - HeapWord* new_top = obj + want_to_allocate; - HeapWord* result = Atomic::cmpxchg(&_top, obj, new_top); - // result can be one of two: - // the old top value: the exchange succeeded - // otherwise: the new value of the top is returned. - if (result == obj) { - assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); - *actual_size = want_to_allocate; - return obj; - } - } else { - return nullptr; - } - } while (true); -} - inline HeapWord* G1HeapRegion::block_start(const void* addr) const { return block_start(addr, parsable_bottom_acquire()); } @@ -225,9 +184,27 @@ inline void G1HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMar } inline HeapWord* G1HeapRegion::par_allocate(size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { - return par_allocate_impl(min_word_size, desired_word_size, actual_word_size); + size_t desired_word_size, + size_t* actual_word_size) { + do { + HeapWord* obj = top(); + size_t available = pointer_delta(end(), obj); + size_t want_to_allocate = MIN2(available, desired_word_size); + if (want_to_allocate >= min_word_size) { + HeapWord* new_top = obj + want_to_allocate; + HeapWord* result = Atomic::cmpxchg(&_top, obj, new_top); + // result can be one of two: + // the old top value: the exchange succeeded + // otherwise: the new value of the top is returned. + if (result == obj) { + assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); + *actual_word_size = want_to_allocate; + return obj; + } + } else { + return nullptr; + } + } while (true); } inline HeapWord* G1HeapRegion::allocate(size_t word_size) { @@ -236,9 +213,20 @@ inline HeapWord* G1HeapRegion::allocate(size_t word_size) { } inline HeapWord* G1HeapRegion::allocate(size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { - return allocate_impl(min_word_size, desired_word_size, actual_word_size); + size_t desired_word_size, + size_t* actual_word_size) { + HeapWord* obj = top(); + size_t available = pointer_delta(end(), obj); + size_t want_to_allocate = MIN2(available, desired_word_size); + if (want_to_allocate >= min_word_size) { + HeapWord* new_top = obj + want_to_allocate; + set_top(new_top); + assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); + *actual_word_size = want_to_allocate; + return obj; + } else { + return nullptr; + } } inline void G1HeapRegion::update_bot() { From 19a8a2baa9e749c7527ff526b2794826f0cdebb3 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 15:42:47 +0000 Subject: [PATCH 76/85] 8335618: Serial: Remove unused definitions in SerialHeap Reviewed-by: iwalulya --- src/hotspot/share/gc/serial/defNewGeneration.hpp | 1 - src/hotspot/share/gc/serial/serialHeap.hpp | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 5c8dd08e40b..a7ee555902a 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -43,7 +43,6 @@ class CSpaceCounters; class OldGenScanClosure; class YoungGenScanClosure; class DefNewTracer; -class ScanWeakRefClosure; class SerialHeap; class STWGCTimer; diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 14e0d737c1a..750bb322b2a 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -72,14 +72,8 @@ class SerialHeap : public CollectedHeap { friend class HeapInspection; friend class GCCauseSetter; friend class VMStructs; -public: friend class VM_PopulateDumpSharedSpace; - enum GenerationType { - YoungGen, - OldGen - }; - private: DefNewGeneration* _young_gen; TenuredGeneration* _old_gen; @@ -124,7 +118,6 @@ class SerialHeap : public CollectedHeap { // Does operations required after initialization has been done. void post_initialize() override; - bool is_young_gen(const Generation* gen) const { return gen == _young_gen; } bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } // Performance Counter support From 8aaec37ace102b55ee1387cfd1967ec3ab662083 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 3 Jul 2024 16:08:34 +0000 Subject: [PATCH 77/85] 8322475: Extend printing for System.map Reviewed-by: sgehwolf, jsjolen --- src/hotspot/os/linux/memMapPrinter_linux.cpp | 183 ++++++++++++++---- src/hotspot/os/linux/procMapsParser.cpp | 125 ++++++++++++ src/hotspot/os/linux/procMapsParser.hpp | 91 +++++++++ src/hotspot/share/nmt/memMapPrinter.cpp | 115 ++++------- src/hotspot/share/nmt/memMapPrinter.hpp | 33 +--- src/hotspot/share/runtime/java.cpp | 2 +- src/hotspot/share/services/attachListener.cpp | 8 +- .../share/services/diagnosticCommand.cpp | 14 +- .../share/services/diagnosticCommand.hpp | 13 +- src/hotspot/share/utilities/ostream.cpp | 7 +- src/hotspot/share/utilities/ostream.hpp | 2 +- .../dcmd/vm/SystemDumpMapTest.java | 23 ++- .../serviceability/dcmd/vm/SystemMapTest.java | 29 +-- .../dcmd/vm/SystemMapTestBase.java | 67 +++++++ 14 files changed, 513 insertions(+), 199 deletions(-) create mode 100644 src/hotspot/os/linux/procMapsParser.cpp create mode 100644 src/hotspot/os/linux/procMapsParser.hpp create mode 100644 test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java diff --git a/src/hotspot/os/linux/memMapPrinter_linux.cpp b/src/hotspot/os/linux/memMapPrinter_linux.cpp index 05d520f6953..0b696b9914e 100644 --- a/src/hotspot/os/linux/memMapPrinter_linux.cpp +++ b/src/hotspot/os/linux/memMapPrinter_linux.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,60 +25,165 @@ #include "precompiled.hpp" -#include "runtime/os.hpp" #include "nmt/memMapPrinter.hpp" +#include "procMapsParser.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + #include -struct ProcMapsInfo { - void* from = 0; - void* to = 0; - char prot[20 + 1]; - char offset[20 + 1]; - char dev[20 + 1]; - char inode[20 + 1]; - char filename[1024 + 1]; - - bool scan_proc_maps_line(const char* line) { - prot[0] = offset[0] = dev[0] = inode[0] = filename[0] = '\0'; - const int items_read = ::sscanf(line, "%p-%p %20s %20s %20s %20s %1024s", - &from, &to, prot, offset, dev, inode, filename); - return items_read >= 2; // need at least from and to +class ProcSmapsSummary { + unsigned _num_mappings; + size_t _vsize; // combined virtual size + size_t _rss; // combined resident set size + size_t _committed; // combined committed size + size_t _shared; // combined shared size + size_t _swapped_out; // combined amount of swapped-out memory + size_t _hugetlb; // combined amount of memory backed by explicit huge pages + size_t _thp; // combined amount of memory backed by THPs +public: + ProcSmapsSummary() : _num_mappings(0), _vsize(0), _rss(0), _committed(0), _shared(0), + _swapped_out(0), _hugetlb(0), _thp(0) {} + void add_mapping(const ProcSmapsInfo& info) { + _num_mappings++; + _vsize += info.vsize(); + _rss += info.rss; + _committed += info.nr ? 0 : info.vsize(); + _shared += info.sh ? info.vsize() : 0; + _swapped_out += info.swap; + _hugetlb += info.private_hugetlb + info.shared_hugetlb; + _thp += info.anonhugepages; + } + + void print_on(const MappingPrintSession& session) const { + outputStream* st = session.out(); + st->print_cr("Number of mappings: %u", _num_mappings); + st->print_cr(" vsize: %zu (" PROPERFMT ")", _vsize, PROPERFMTARGS(_vsize)); + st->print_cr(" rss: %zu (" PROPERFMT ")", _rss, PROPERFMTARGS(_rss)); + st->print_cr(" committed: %zu (" PROPERFMT ")", _committed, PROPERFMTARGS(_committed)); + st->print_cr(" shared: %zu (" PROPERFMT ")", _shared, PROPERFMTARGS(_shared)); + st->print_cr(" swapped out: %zu (" PROPERFMT ")", _swapped_out, PROPERFMTARGS(_swapped_out)); + st->print_cr(" using thp: %zu (" PROPERFMT ")", _thp, PROPERFMTARGS(_thp)); + st->print_cr(" hugetlb: %zu (" PROPERFMT ")", _hugetlb, PROPERFMTARGS(_hugetlb)); } }; -class LinuxMappingPrintInformation : public MappingPrintInformation { - const ProcMapsInfo _info; +class ProcSmapsPrinter { + const MappingPrintSession& _session; public: + ProcSmapsPrinter(const MappingPrintSession& session) : + _session(session) + {} - LinuxMappingPrintInformation(const void* from, const void* to, const ProcMapsInfo* info) : - MappingPrintInformation(from, to), _info(*info) {} + void print_single_mapping(const ProcSmapsInfo& info) const { + outputStream* st = _session.out(); +#define INDENT_BY(n) \ + if (st->fill_to(n) == 0) { \ + st->print(" "); \ + } + st->print(PTR_FORMAT "-" PTR_FORMAT, p2i(info.from), p2i(info.to)); + INDENT_BY(38); + st->print("%12zu", info.vsize()); + INDENT_BY(51); + st->print("%s", info.prot); + INDENT_BY(56); + st->print("%12zu", info.rss); + INDENT_BY(69); + st->print("%12zu", info.private_hugetlb); + INDENT_BY(82); + st->print(EXACTFMT, EXACTFMTARGS(info.kernelpagesize)); + { + INDENT_BY(87); + int num_printed = 0; +#define PRINTIF(cond, s) \ + if (cond) { \ + st->print("%s%s", (num_printed > 0 ? "," : ""), s); \ + num_printed++; \ + } + PRINTIF(info.sh, "shrd"); + PRINTIF(!info.nr, "com"); + PRINTIF(info.swap > 0, "swap"); + PRINTIF(info.ht, "huge"); + PRINTIF(info.anonhugepages > 0, "thp"); + PRINTIF(info.hg, "thpad"); + PRINTIF(info.nh, "nothp"); + if (num_printed == 0) { + st->print("-"); + } +#undef PRINTIF + } + INDENT_BY(104); + if (!_session.print_nmt_info_for_region(info.from, info.to)) { + st->print("-"); + } + INDENT_BY(142); + st->print_raw(info.filename[0] == '\0' ? "-" : info.filename); + #undef INDENT_BY + st->cr(); + } - void print_OS_specific_details(outputStream* st) const override { - st->print("%s %s ", _info.prot, _info.offset); + void print_legend() const { + outputStream* st = _session.out(); + st->print_cr("from, to, vsize: address range and size"); + st->print_cr("prot: protection"); + st->print_cr("rss: resident set size"); + st->print_cr("hugetlb: size of private hugetlb pages"); + st->print_cr("pgsz: page size"); + st->print_cr("notes: mapping information (detail mode only)"); + st->print_cr(" shrd: mapping is shared"); + st->print_cr(" com: mapping committed (swap space reserved)"); + st->print_cr(" swap: mapping partly or completely swapped out"); + st->print_cr(" thp: mapping uses THP"); + st->print_cr(" thpad: mapping is THP-madvised"); + st->print_cr(" nothp: mapping is forbidden to use THP"); + st->print_cr(" huge: mapping uses hugetlb pages"); + st->print_cr("vm info: VM information (requires NMT)"); + { + streamIndentor si(st, 16); + _session.print_nmt_flag_legend(); + } + st->print_cr("file: file mapped, if mapping is not anonymous"); } - const char* filename() const override { return _info.filename; } + void print_header() const { + outputStream* st = _session.out(); + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 + // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 + // 0x0000000414000000-0x0000000453000000 123456789012 rw-p 123456789012 123456789012 16g thp,thpadv STACK-340754-Monitor-Deflation-Thread /shared/tmp.txt + st->print_cr("from to vsize prot rss hugetlb pgsz notes info file"); + st->print_cr("========================================================================================================================================================================"); + } }; -void MemMapPrinter::pd_print_header(outputStream* st) { - st->print_cr("size prot offset What"); -} - -void MemMapPrinter::pd_iterate_all_mappings(MappingPrintClosure& closure) { - FILE* f = os::fopen("/proc/self/maps", "r"); +void MemMapPrinter::pd_print_all_mappings(const MappingPrintSession& session) { + constexpr char filename[] = "/proc/self/smaps"; + FILE* f = os::fopen(filename, "r"); if (f == nullptr) { + session.out()->print_cr("Cannot open %s", filename); return; } - constexpr size_t linesize = sizeof(ProcMapsInfo); - char line[linesize]; - while (fgets(line, sizeof(line), f) == line) { - line[sizeof(line) - 1] = '\0'; - ProcMapsInfo info; - if (info.scan_proc_maps_line(line)) { - LinuxMappingPrintInformation mapinfo(info.from, info.to, &info); - closure.do_it(&mapinfo); - } + + ProcSmapsPrinter printer(session); + ProcSmapsSummary summary; + + outputStream* const st = session.out(); + + printer.print_legend(); + st->cr(); + printer.print_header(); + + ProcSmapsInfo info; + ProcSmapsParser parser(f); + while (parser.parse_next(info)) { + printer.print_single_mapping(info); + summary.add_mapping(info); } + st->cr(); + + summary.print_on(session); + st->cr(); + ::fclose(f); } diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp new file mode 100644 index 00000000000..6dfd49a0596 --- /dev/null +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "procMapsParser.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" + +static bool is_lowercase_hex(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +static size_t max_mapping_line_len() { + return 100 + // everything but the file name + os::vm_page_size() // the file name (kernel limits /proc/pid/cmdline to one page + ; +} + +ProcSmapsParser::ProcSmapsParser(FILE* f) : + _f(f), _linelen(max_mapping_line_len()), _line(nullptr) { + assert(_f != nullptr, "Invalid file handle given"); + _line = NEW_C_HEAP_ARRAY(char, max_mapping_line_len(), mtInternal); + _line[0] = '\0'; +} + +ProcSmapsParser::~ProcSmapsParser() { + FREE_C_HEAP_ARRAY(char, _line); +} + +bool ProcSmapsParser::read_line() { + _line[0] = '\0'; + return ::fgets(_line, _linelen, _f) != nullptr; +} + +bool ProcSmapsParser::is_header_line() { + // e.g. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] + return is_lowercase_hex(_line[0]); // All non-header lines in /proc/pid/smaps start with upper-case letters. +} + +void ProcSmapsParser::scan_header_line(ProcSmapsInfo& out) { + const int items_read = ::sscanf(_line, "%p-%p %20s %*s %*s %*s %1024s", + &out.from, &out.to, out.prot, out.filename); + assert(items_read >= 2, "Expected header_line"); +} + +void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) { +#define SCAN(key, var) \ + if (::sscanf(_line, key ": %zu kB", &var) == 1) { \ + var *= K; \ + return; \ + } + SCAN("KernelPageSize", out.kernelpagesize); + SCAN("Rss", out.rss); + SCAN("AnonHugePages", out.anonhugepages); + SCAN("Private_Hugetlb", out.private_hugetlb); + SCAN("Shared_Hugetlb", out.shared_hugetlb); + SCAN("Swap", out.swap); + int i = 0; +#undef SCAN + // scan some flags too + if (strncmp(_line, "VmFlags:", 8) == 0) { +#define SCAN(flag) { out.flag = (::strstr(_line + 8, " " #flag) != nullptr); } + SCAN(rd); + SCAN(wr); + SCAN(ex); + SCAN(nr); + SCAN(sh); + SCAN(hg); + SCAN(ht); + SCAN(nh); +#undef SCAN + } +} + +// Starts or continues parsing. Returns true on success, +// false on EOF or on error. +bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { + + // Information about a single mapping reaches across several lines. + out.reset(); + + // Read header line, unless we already read it + if (_line[0] == '\0') { + if (!read_line()) { + return false; + } + } + assert(is_header_line(), "Not a header line: \"%s\".", _line); + scan_header_line(out); + + // Now read until we encounter the next header line or EOF or an error. + bool ok = false, stop = false; + do { + ok = read_line(); + stop = !ok || is_header_line(); + if (!stop) { + scan_additional_line(out); + } + } while (!stop); + + return ok; +} diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp new file mode 100644 index 00000000000..0971c4fb084 --- /dev/null +++ b/src/hotspot/os/linux/procMapsParser.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_PROCMAPSPARSER_HPP +#define OS_LINUX_PROCMAPSPARSER_HPP + +#include "utilities/globalDefinitions.hpp" + +// This header exposes two simple parsers for /proc/pid/maps and +// /proc/pid/smaps. +// +// Usage: +// +// FILE* f = fopen(...) +// ProcSMapsParser parser(f); +// ProcSMapsInfo info; +// while (parser.parse_next(info)) { ... } + +struct ProcSmapsInfo { + void* from; + void* to; + char prot[20 + 1]; + char filename[1024 + 1]; + size_t kernelpagesize; + size_t rss; + size_t private_hugetlb; + size_t shared_hugetlb; + size_t anonhugepages; + size_t swap; + bool rd, wr, ex; + bool sh; // shared + bool nr; // no reserve + bool hg; // thp-advised + bool ht; // uses hugetlb pages + bool nh; // thp forbidden + + size_t vsize() const { + return from < to ? pointer_delta(to, from, 1) : 0; + } + + void reset() { + from = to = nullptr; + prot[0] = filename[0] = '\0'; + kernelpagesize = rss = private_hugetlb = shared_hugetlb = anonhugepages = swap = 0; + rd = wr = ex = sh = nr = hg = ht = nh = false; + } +}; + +class ProcSmapsParser { + FILE* _f; + const size_t _linelen; + char* _line; + + bool read_line(); // sets had_error in case of error + bool is_header_line(); + void scan_header_line(ProcSmapsInfo& out); + void scan_additional_line(ProcSmapsInfo& out); + +public: + + ProcSmapsParser(FILE* f); + ~ProcSmapsParser(); + + // Starts or continues parsing. Returns true on success, + // false on EOF or on error. + bool parse_next(ProcSmapsInfo& out); +}; + +#endif // OS_LINUX_PROCMAPSPARSER_HPP diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index 5480904d57c..5f920b102a9 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -27,8 +27,9 @@ #ifdef LINUX -#include "logging/logAsyncWriter.hpp" #include "gc/shared/collectedHeap.hpp" +#include "logging/logAsyncWriter.hpp" +#include "memory/allocation.hpp" #include "memory/universe.hpp" #include "memory/resourceArea.hpp" #include "nmt/memflags.hpp" @@ -42,7 +43,6 @@ #include "runtime/threadSMR.hpp" #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" // Note: throughout this code we will use the term "VMA" for OS system level memory mapping @@ -160,13 +160,6 @@ class CachedNMTInformation : public VirtualMemoryWalker { bool fill_from_nmt() { return VirtualMemoryTracker::walk_virtual_memory(this); } - - void print_on(outputStream* st) const { - for (size_t i = 0; i < _count; i ++) { - st->print_cr(PTR_FORMAT "-" PTR_FORMAT " %s", p2i(_ranges[i].from), p2i(_ranges[i].to), - NMTUtil::flag_to_enum_name(_flags[i])); - } - } }; /////// Thread information ////////////////////////// @@ -198,7 +191,16 @@ struct GCThreadClosure : public ThreadClosure { }; static void print_thread_details(uintx thread_id, const char* name, outputStream* st) { - st->print("(" UINTX_FORMAT " \"%s\")", (uintx)thread_id, name); + // avoid commas and spaces in output to ease post-processing via awk + char tmp[64]; + stringStream ss(tmp, sizeof(tmp)); + ss.print(":" UINTX_FORMAT "-%s", (uintx)thread_id, name); + for (int i = 0; tmp[i] != '\0'; i++) { + if (!isalnum(tmp[i])) { + tmp[i] = '-'; + } + } + st->print_raw(tmp); } // Given a region [from, to), if it intersects a known thread stack, print detail infos about that thread. @@ -230,41 +232,18 @@ static void print_thread_details_for_supposed_stack_address(const void* from, co /////////////// -static void print_legend(outputStream* st) { -#define DO(flag, shortname, text) st->print_cr("%10s %s", shortname, text); +MappingPrintSession::MappingPrintSession(outputStream* st, const CachedNMTInformation& nmt_info) : + _out(st), _nmt_info(nmt_info) +{} + +void MappingPrintSession::print_nmt_flag_legend() const { +#define DO(flag, shortname, text) _out->indent(); _out->print_cr("%10s: %s", shortname, text); NMT_FLAGS_DO(DO) #undef DO } -MappingPrintClosure::MappingPrintClosure(outputStream* st, bool human_readable, const CachedNMTInformation& nmt_info) : - _out(st), _human_readable(human_readable), - _total_count(0), _total_vsize(0), _nmt_info(nmt_info) -{} - -void MappingPrintClosure::do_it(const MappingPrintInformation* info) { - - _total_count++; - - const void* const vma_from = info->from(); - const void* const vma_to = info->to(); - - // print from, to - _out->print(PTR_FORMAT " - " PTR_FORMAT " ", p2i(vma_from), p2i(vma_to)); - const size_t size = pointer_delta(vma_to, vma_from, 1); - _total_vsize += size; - - // print mapping size - if (_human_readable) { - _out->print(PROPERFMT " ", PROPERFMTARGS(size)); - } else { - _out->print("%11zu", size); - } - - assert(info->from() <= info->to(), "Invalid VMA"); - _out->fill_to(53); - info->print_OS_specific_details(_out); - _out->fill_to(70); - +bool MappingPrintSession::print_nmt_info_for_region(const void* vma_from, const void* vma_to) const { + int num_printed = 0; // print NMT information, if available if (MemTracker::enabled()) { // Correlate vma region (from, to) with NMT region(s) we collected previously. @@ -273,59 +252,33 @@ void MappingPrintClosure::do_it(const MappingPrintInformation* info) { for (int i = 0; i < mt_number_of_types; i++) { const MEMFLAGS flag = (MEMFLAGS)i; if (flags.has_flag(flag)) { + if (num_printed > 0) { + _out->put(','); + } _out->print("%s", get_shortname_for_nmt_flag(flag)); if (flag == mtThreadStack) { print_thread_details_for_supposed_stack_address(vma_from, vma_to, _out); } - _out->print(" "); + num_printed++; } } } } - - // print file name, if available - const char* f = info->filename(); - if (f != nullptr) { - _out->print_raw(f); - } - _out->cr(); -} - -void MemMapPrinter::print_header(outputStream* st) { - st->print( -#ifdef _LP64 - // 0x0000000000000000 - 0x0000000000000000 - "from to " -#else - // 0x00000000 - 0x00000000 - "from to " -#endif - ); - // Print platform-specific columns - pd_print_header(st); + return num_printed > 0; } -void MemMapPrinter::print_all_mappings(outputStream* st, bool human_readable) { - // First collect all NMT information +void MemMapPrinter::print_all_mappings(outputStream* st) { CachedNMTInformation nmt_info; - nmt_info.fill_from_nmt(); - DEBUG_ONLY(nmt_info.print_on(st);) st->print_cr("Memory mappings:"); - if (!MemTracker::enabled()) { - st->cr(); - st->print_cr(" (NMT is disabled, will not annotate mappings)."); + // Prepare NMT info cache. But only do so if we print individual mappings, + // otherwise, we won't need it and can save that work. + if (MemTracker::enabled()) { + nmt_info.fill_from_nmt(); + } else { + st->print_cr("NMT is disabled. VM info not available."); } - st->cr(); - - print_legend(st); - st->print_cr("(*) - Mapping contains data from multiple regions"); - st->cr(); - - pd_print_header(st); - MappingPrintClosure closure(st, human_readable, nmt_info); - pd_iterate_all_mappings(closure); - st->print_cr("Total: " UINTX_FORMAT " mappings with a total vsize of %zu (" PROPERFMT ")", - closure.total_count(), closure.total_vsize(), PROPERFMTARGS(closure.total_vsize())); + MappingPrintSession session(st, nmt_info); + pd_print_all_mappings(session); } #endif // LINUX diff --git a/src/hotspot/share/nmt/memMapPrinter.hpp b/src/hotspot/share/nmt/memMapPrinter.hpp index 67706c4d4d7..aa35a830001 100644 --- a/src/hotspot/share/nmt/memMapPrinter.hpp +++ b/src/hotspot/share/nmt/memMapPrinter.hpp @@ -35,39 +35,20 @@ class outputStream; class CachedNMTInformation; -class MappingPrintInformation { - const void* const _from; - const void* const _to; -public: - MappingPrintInformation(const void* from, const void* to) : _from(from), _to(to) {} - const void* from() const { return _from; } - const void* to() const { return _to; } - // Will be called for each mapping before VM annotations are printed. - virtual void print_OS_specific_details(outputStream* st) const {} - // If mapping is backed by a file, the name of that file - virtual const char* filename() const { return nullptr; } -}; - -class MappingPrintClosure { +class MappingPrintSession { outputStream* const _out; - const bool _human_readable; - uintx _total_count; - size_t _total_vsize; const CachedNMTInformation& _nmt_info; public: - MappingPrintClosure(outputStream* st, bool human_readable, const CachedNMTInformation& nmt_info); - void do_it(const MappingPrintInformation* info); // returns false if timeout reached. - uintx total_count() const { return _total_count; } - size_t total_vsize() const { return _total_vsize; } + MappingPrintSession(outputStream* st, const CachedNMTInformation& nmt_info); + bool print_nmt_info_for_region(const void* from, const void* to) const; + void print_nmt_flag_legend() const; + outputStream* out() const { return _out; } }; class MemMapPrinter : public AllStatic { - static void pd_print_header(outputStream* st); - static void print_header(outputStream* st); - static void pd_iterate_all_mappings(MappingPrintClosure& closure); + static void pd_print_all_mappings(const MappingPrintSession& session); public: - static void mark_page_malloced(const void* p, MEMFLAGS f); - static void print_all_mappings(outputStream* st, bool human_readable); + static void print_all_mappings(outputStream* st); }; #endif // LINUX diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 674716a8598..7ffe56d9715 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -487,7 +487,7 @@ void before_exit(JavaThread* thread, bool halt) { CodeCache::write_perf_map(); } if (PrintMemoryMapAtExit) { - MemMapPrinter::print_all_mappings(tty, false); + MemMapPrinter::print_all_mappings(tty); } #endif diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index d1531e1ec01..36931531a4e 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -395,7 +395,13 @@ void AttachListenerThread::thread_entry(JavaThread* thread, TRAPS) { } ResourceMark rm; - bufferedStream st; + // jcmd output can get lengthy. As long as we miss jcmd continuous streaming output + // and instead just send the output in bulk, make sure large command output does not + // cause asserts. We still retain a max cap, but dimensioned in a way that makes it + // highly unlikely we should ever hit it under normal conditions. + constexpr size_t initial_size = 1 * M; + constexpr size_t max_size = 3 * G; + bufferedStream st(initial_size, max_size); jint res = JNI_OK; // handle special detachall operation diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 4b8eae8a413..7d2325c16b6 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -1180,23 +1180,17 @@ void CompilationMemoryStatisticDCmd::execute(DCmdSource source, TRAPS) { #ifdef LINUX -SystemMapDCmd::SystemMapDCmd(outputStream* output, bool heap) : - DCmdWithParser(output, heap), - _human_readable("-H", "Human readable format", "BOOLEAN", false, "false") { - _dcmdparser.add_dcmd_option(&_human_readable); -} +SystemMapDCmd::SystemMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} void SystemMapDCmd::execute(DCmdSource source, TRAPS) { - MemMapPrinter::print_all_mappings(output(), _human_readable.value()); + MemMapPrinter::print_all_mappings(output()); } static constexpr char default_filename[] = "vm_memory_map_.txt"; SystemDumpMapDCmd::SystemDumpMapDCmd(outputStream* output, bool heap) : - DCmdWithParser(output, heap), - _human_readable("-H", "Human readable format", "BOOLEAN", false, "false"), + DCmdWithParser(output, heap), _filename("-F", "file path", "STRING", false, default_filename) { - _dcmdparser.add_dcmd_option(&_human_readable); _dcmdparser.add_dcmd_option(&_filename); } @@ -1214,7 +1208,7 @@ void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) { if (!MemTracker::enabled()) { output()->print_cr("(NMT is disabled, will not annotate mappings)."); } - MemMapPrinter::print_all_mappings(&fs, _human_readable.value()); + MemMapPrinter::print_all_mappings(&fs); // For the readers convenience, resolve path name. char tmp[JVM_MAXPATHLEN]; const char* absname = os::Posix::realpath(name, tmp, sizeof(tmp)); diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 88a48970810..ec3469c8d15 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -983,16 +983,14 @@ class CompilationMemoryStatisticDCmd: public DCmdWithParser { #ifdef LINUX -class SystemMapDCmd : public DCmdWithParser { - DCmdArgument _human_readable; +class SystemMapDCmd : public DCmd { public: - static int num_arguments() { return 1; } SystemMapDCmd(outputStream* output, bool heap); static const char* name() { return "System.map"; } static const char* description() { return "Prints an annotated process memory map of the VM process (linux only)."; } - static const char* impact() { return "Low"; } + static const char* impact() { return "Medium; can be high for very large java heaps."; } static const JavaPermission permission() { JavaPermission p = {"java.lang.management.ManagementPermission", "control", nullptr}; @@ -1002,16 +1000,15 @@ class SystemMapDCmd : public DCmdWithParser { }; class SystemDumpMapDCmd : public DCmdWithParser { - DCmdArgument _human_readable; DCmdArgument _filename; public: - static int num_arguments() { return 2; } + static int num_arguments() { return 1; } SystemDumpMapDCmd(outputStream* output, bool heap); static const char* name() { return "System.dump_map"; } static const char* description() { return "Dumps an annotated process memory map to an output file (linux only)."; } - static const char* impact() { return "Low"; } + static const char* impact() { return "Medium; can be high for very large java heaps."; } static const JavaPermission permission() { JavaPermission p = {"java.lang.management.ManagementPermission", "control", nullptr}; diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 5d6731785a3..b8f27fbd413 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -191,9 +191,10 @@ void outputStream::print_raw(const char* str, size_t len) { write(str, len); } -void outputStream::fill_to(int col) { - int need_fill = col - position(); +int outputStream::fill_to(int col) { + const int need_fill = MAX2(col - position(), 0); sp(need_fill); + return need_fill; } void outputStream::move_to(int col, int slop, int min_space) { @@ -1037,7 +1038,7 @@ void bufferedStream::write(const char* s, size_t len) { const size_t reasonable_cap = MAX2(100 * M, buffer_max * 2); if (end > reasonable_cap) { // In debug VM, assert right away. - assert(false, "Exceeded max buffer size for this string."); + assert(false, "Exceeded max buffer size for this string (\"%.200s...\").", buffer); // Release VM: silently truncate. We do this since these kind of errors // are both difficult to predict with testing (depending on logging content) // and usually not serious enough to kill a production VM for it. diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index bff682a3e5a..beb02309d3f 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -101,7 +101,7 @@ class outputStream : public CHeapObjBase { void dec(int n) { _indentation -= n; }; int indentation() const { return _indentation; } void set_indentation(int i) { _indentation = i; } - void fill_to(int col); + int fill_to(int col); void move_to(int col, int slop = 6, int min_space = 2); // Automatic indentation: diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java index 347e8884096..eb0b6bd8566 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import jdk.test.lib.process.OutputAnalyzer; import java.io.*; -import java.util.ArrayList; import java.util.HashSet; import java.util.regex.Pattern; @@ -41,9 +40,9 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run testng SystemDumpMapTest + * @run testng/othervm -XX:+UsePerfData SystemDumpMapTest */ -public class SystemDumpMapTest { +public class SystemDumpMapTest extends SystemMapTestBase { private void run_test(CommandExecutor executor, boolean useDefaultFileName) { @@ -64,18 +63,22 @@ private void run_test(CommandExecutor executor, boolean useDefaultFileName) { boolean NMTOff = output.contains("NMT is disabled"); String regexBase = ".*0x\\p{XDigit}+ - 0x\\p{XDigit}+ +\\d+"; HashSet patterns = new HashSet<>(); - patterns.add(Pattern.compile(regexBase + ".*jvm.*")); + for (String s: shouldMatchUnconditionally) { + patterns.add(Pattern.compile(s)); + } if (!NMTOff) { // expect VM annotations if NMT is on - patterns.add(Pattern.compile(regexBase + ".*JAVAHEAP.*")); - patterns.add(Pattern.compile(regexBase + ".*META.*")); - patterns.add(Pattern.compile(regexBase + ".*CODE.*")); - patterns.add(Pattern.compile(regexBase + ".*STACK.*main.*")); + for (String s: shouldMatchIfNMTIsEnabled) { + patterns.add(Pattern.compile(s)); + } } + do { String line = reader.readLine(); if (line != null) { + System.out.println(" " + line); for (Pattern pat : patterns) { if (pat.matcher(line).matches()) { + System.out.println(">>> matches " + pat); patterns.remove(pat); break; } diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java index 9fb8efe5a71..43857a1f039 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,6 @@ import jdk.test.lib.dcmd.JMXExecutor; import jdk.test.lib.process.OutputAnalyzer; -import java.io.*; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.Deque; -import java.util.HashSet; -import java.util.regex.Pattern; - /* * @test * @summary Test of diagnostic command System.map @@ -43,21 +36,19 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run testng SystemMapTest + * @run testng/othervm -XX:+UsePerfData SystemMapTest */ -public class SystemMapTest { +public class SystemMapTest extends SystemMapTestBase { public void run(CommandExecutor executor) { OutputAnalyzer output = executor.execute("System.map"); - output.reportDiagnosticSummary(); boolean NMTOff = output.contains("NMT is disabled"); - - String regexBase = ".*0x\\p{XDigit}+ - 0x\\p{XDigit}+ +\\d+"; - output.shouldMatch(regexBase + ".*jvm.*"); + for (String s: shouldMatchUnconditionally) { + output.shouldMatch(s); + } if (!NMTOff) { // expect VM annotations if NMT is on - output.shouldMatch(regexBase + ".*JAVAHEAP.*"); - output.shouldMatch(regexBase + ".*META.*"); - output.shouldMatch(regexBase + ".*CODE.*"); - output.shouldMatch(regexBase + ".*STACK.*main.*"); + for (String s: shouldMatchIfNMTIsEnabled) { + output.shouldMatch(s); + } } } diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java new file mode 100644 index 00000000000..20dc8d70d7a --- /dev/null +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * 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. + */ + +public class SystemMapTestBase { + + // e.g. + // 0x00000007ff800000-0x00000007ff91a000 1155072 rw-p 1155072 0 4K com JAVAHEAP /shared/projects/openjdk/jdk-jdk/output-fastdebug/images/jdk/lib/server/classes.jsa + private static final String range = "0x\\p{XDigit}+-0x\\p{XDigit}+"; + private static final String space = " +"; + private static final String someSize = "\\d+"; + private static final String pagesize = "(4K|8K|16K|64K|2M|16M|64M)"; + private static final String prot = "[rwsxp-]+"; + + private static final String regexBase = range + space + + someSize + space + + prot + space + + someSize + space + + someSize + space + + pagesize + space; + + private static final String regexBase_committed = regexBase + "com.*"; + private static final String regexBase_shared_and_committed = regexBase + "shrd,com.*"; + + protected static final String shouldMatchUnconditionally[] = { + // java launcher + regexBase_committed + "/bin/java", + // libjvm + regexBase_committed + "/lib/.*/libjvm.so", + // vdso library, should be part of all user space apps on all architectures OpenJDK supports. + regexBase_committed + "\\[vdso\\]", + // we should see the hs-perf data file, and it should appear as shared as well as committed + regexBase_shared_and_committed + "hsperfdata_.*" + }; + + protected static final String shouldMatchIfNMTIsEnabled[] = { + regexBase_committed + "JAVAHEAP.*", + // metaspace + regexBase_committed + "META.*", + // parts of metaspace should be uncommitted + regexBase + "-" + space + "META.*", + // code cache + regexBase_committed + "CODE.*", + // Main thread stack + regexBase_committed + "STACK.*main.*" + }; +} From 13b782c3de9a470a7cf1db9d5111ce19faf28729 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 3 Jul 2024 16:10:22 +0000 Subject: [PATCH 78/85] 8334554: RISC-V: verify & fix perf of string comparison Reviewed-by: rehn, luhenry, fyang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 21 +++++++++---- .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 2 +- src/hotspot/cpu/riscv/riscv_v.ad | 30 +++++++++++++++++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 9ce197a44bf..887baa4a506 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2326,12 +2326,13 @@ void C2_MacroAssembler::expand_bits_l_v(Register dst, Register src, Register mas } void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2, - VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE) { + VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE, + Assembler::LMUL lmul) { Label loop; Assembler::SEW sew = islatin ? Assembler::e8 : Assembler::e16; bind(loop); - vsetvli(tmp1, cnt, sew, Assembler::m2); + vsetvli(tmp1, cnt, sew, lmul); vlex_v(vr1, a1, sew); vlex_v(vr2, a2, sew); vmsne_vv(vrs, vr1, vr2); @@ -2357,7 +2358,7 @@ void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register resul mv(result, false); - element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, true, DONE); + element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, true, DONE, Assembler::m2); bind(DONE); BLOCK_COMMENT("} string_equals_v"); @@ -2410,7 +2411,7 @@ void C2_MacroAssembler::arrays_equals_v(Register a1, Register a2, Register resul la(a1, Address(a1, base_offset)); la(a2, Address(a2, base_offset)); - element_compare(a1, a2, result, cnt1, tmp1, tmp2, v2, v4, v2, elem_size == 1, DONE); + element_compare(a1, a2, result, cnt1, tmp1, tmp2, v2, v4, v2, elem_size == 1, DONE, Assembler::m2); bind(DONE); @@ -2445,8 +2446,18 @@ void C2_MacroAssembler::string_compare_v(Register str1, Register str2, Register mv(cnt2, cnt1); bind(L); + // We focus on the optimization of small sized string. + // Please check below document for string size distribution statistics. + // https://cr.openjdk.org/~shade/density/string-density-report.pdf if (str1_isL == str2_isL) { // LL or UU - element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v2, v4, v2, encLL, DIFFERENCE); + // Below construction of v regs and lmul is based on test on 2 different boards, + // vlen == 128 and vlen == 256 respectively. + if (!encLL && MaxVectorSize == 16) { // UU + element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v4, v8, v4, encLL, DIFFERENCE, Assembler::m4); + } else { // UU + MaxVectorSize or LL + element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v2, v4, v2, encLL, DIFFERENCE, Assembler::m2); + } + j(DONE); } else { // LU or UL Register strL = encLU ? str1 : str2; diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 9988b98fa2c..07041fe0850 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -37,7 +37,7 @@ Register tmp1, Register tmp2, VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, - bool is_latin, Label& DONE); + bool is_latin, Label& DONE, Assembler::LMUL lmul); void compress_bits_v(Register dst, Register src, Register mask, bool is_long); void expand_bits_v(Register dst, Register src, Register mask, bool is_long); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 841e8cb260c..1a51d7583c9 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -3605,14 +3605,37 @@ instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, ins_pipe(pipe_class_memory); %} +instruct vstring_compareU_128b(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V4 v4, vReg_V5 v5, vReg_V6 v6, vReg_V7 v7, + vReg_V8 v8, vReg_V9 v9, vReg_V10 v10, vReg_V11 v11, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU && + MaxVectorSize == 16); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v4, TEMP v5, TEMP v6, TEMP v7, TEMP v8, TEMP v9, TEMP v10, TEMP v11); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} + instruct vstring_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, iRegI_R10 result, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, iRegP_R28 tmp1, iRegL_R29 tmp2) %{ - predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU); + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU && + MaxVectorSize > 16); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, - TEMP v2, TEMP v3, TEMP v4, TEMP v5); + TEMP v2, TEMP v3, TEMP v4, TEMP v5); format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} ins_encode %{ @@ -3624,6 +3647,7 @@ instruct vstring_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_ %} ins_pipe(pipe_class_memory); %} + instruct vstring_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, iRegI_R10 result, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, iRegP_R28 tmp1, iRegL_R29 tmp2) @@ -3631,7 +3655,7 @@ instruct vstring_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_ predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, - TEMP v2, TEMP v3, TEMP v4, TEMP v5); + TEMP v2, TEMP v3, TEMP v4, TEMP v5); format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareL" %} ins_encode %{ From 9a91865ff38f6fbb48b9aba5028e0b529d9bce76 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Jul 2024 16:29:52 +0000 Subject: [PATCH 79/85] 8335395: G1: Verification does not detect references into Free regions Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp | 1 + src/hotspot/share/gc/g1/g1HeapRegion.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 49f1c82a98a..63eceb4a5ba 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -253,6 +253,7 @@ inline bool G1CollectedHeap::is_obj_filler(const oop obj) { } inline bool G1CollectedHeap::is_obj_dead(const oop obj, const G1HeapRegion* hr) const { + assert(!hr->is_free(), "looking up obj " PTR_FORMAT " in Free region %u", p2i(obj), hr->hrm_index()); if (hr->is_in_parsable_area(obj)) { // This object is in the parsable part of the heap, live unless scrubbed. return is_obj_filler(obj); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 94382a3b256..d611cf7f947 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -547,7 +547,10 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { } bool failed() const { - return !_is_in_heap || this->_g1h->is_obj_dead_cond(this->_obj, _vo); + return !_is_in_heap || + // is_obj_dead* assume that obj is not in a Free region. + this->_g1h->heap_region_containing(this->_obj)->is_free() || + this->_g1h->is_obj_dead_cond(this->_obj, _vo); } void report_error() { From 68ffec9800b798927a050900a2d47000aa18ef30 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 3 Jul 2024 20:43:08 +0000 Subject: [PATCH 80/85] 8335479: JFR: Missing documentation for -XX:StartFlightRecording Reviewed-by: mgronlun --- src/java.base/share/man/java.1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 839d46e1228..133710abc25 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -1710,10 +1710,12 @@ This prevents the JVM from exiting and keeps the process active so that you can attach a debugger to it to investigate the cause of the error. By default, this option is disabled. .TP -\f[V]-XX:StartFlightRecording=\f[R]\f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] +\f[V]-XX:StartFlightRecording:\f[R]\f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] Starts a JFR recording for the Java application. This option is equivalent to the \f[V]JFR.start\f[R] diagnostic command that starts a recording during runtime. +\f[V]-XX:StartFlightRecording:help\f[R] prints available options and +example command lines. You can set the following \f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] entries when starting a JFR recording: .RS @@ -1760,6 +1762,8 @@ written when the recording is stopped, for example: .PP If %p and/or %t is specified in the filename, it expands to the JVM\[aq]s PID and the current timestamp, respectively. +The filename may also be a directory in which case, the filename is +generated from the PID and the current date in the specified directory. .RE .TP \f[V]name=\f[R]\f[I]identifier\f[R] @@ -1840,6 +1844,9 @@ The whitespace delimiter can be omitted for timespan values, i.e. 20ms. For more information about the settings syntax, see Javadoc of the jdk.jfr package. +.PP +To only see warnings and errors from JFR during startup set +-Xlog:jfr+startup=warning. .RE .TP \f[V]-XX:ThreadStackSize=\f[R]\f[I]size\f[R] From 587535c5b9bb258836b47c3a8c41ffb91bbfc131 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 3 Jul 2024 21:42:08 +0000 Subject: [PATCH 81/85] 8334545: runtime/ClassInitErrors/TestStackOverflowDuringInit.java fails after JDK-8294960 Reviewed-by: iklam, stuefe --- test/hotspot/jtreg/ProblemList.txt | 1 - .../TestStackOverflowDuringInit.java | 49 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index c55790de5ca..d7088408ab8 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -108,7 +108,6 @@ runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 -runtime/ClassInitErrors/TestStackOverflowDuringInit.java 8334545 generic-all applications/jcstress/copy.java 8229852 linux-all diff --git a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java index 43a9985d835..3917abe85ad 100644 --- a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java +++ b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,15 @@ /** * @test - * @bug 8309034 + * @bug 8309034 8334545 * @summary Test that when saving a class initialization failure caused by * a StackOverflowError, that we record the SOE as the underlying * cause, even if we can't create the ExceptionInInitializerError - * @requires os.simpleArch == "x64" - * @comment The reproducer only fails in the desired way on x64. - * @requires vm.flagless * @comment This test could easily be perturbed so don't allow flag settings. - * - * @run main/othervm -Xss160K -Xint TestStackOverflowDuringInit + * @requires vm.flagless + * @comment Run with the smallest stack possible to limit the execution time. + * This is the smallest stack that is supported by all platforms. + * @run main/othervm -Xss240K -Xint TestStackOverflowDuringInit */ import java.io.ByteArrayOutputStream; @@ -51,11 +50,33 @@ public class TestStackOverflowDuringInit { // of another class, which is where we will fail to create the EIIE. // Even then this is non-trivial, only the use of Long.valueOf from // the original reproducer seems to trigger SOE in just the right places. + // Later changes to the JDK meant that LongCache was initialized before + // the test even started under jtreg so we define local versions. + + static class LongCache { + // Must have a static initializer + static { + System.out.println("LongCache is initializing"); + } + static java.lang.Long valueOf(long l) { + return Long.valueOf(l); + } + } + + static class MyLong { + static java.lang.Long valueOf(long l) { + if (l > -128 && l < 127) { + return LongCache.valueOf(l); + } else { + return Long.valueOf(l); + } + } + } static void recurse() { try { - // This will initialize Long but not touch LongCache. - Long.valueOf(1024L); + // This will initialize MyLong but not touch LongCache. + MyLong.valueOf(1024L); recurse(); } finally { // This will require initializing LongCache, which will @@ -63,14 +84,20 @@ static void recurse() { // will be marked erroneous. As we unwind and again execute this // we will throw NoClassDefFoundError due to the erroneous // state of LongCache. - Long.valueOf(0); + MyLong.valueOf(0); } } public static void main(String[] args) throws Exception { - String expected = "java.lang.NoClassDefFoundError: Could not initialize class java.lang.Long$LongCache"; + String expected = "java.lang.NoClassDefFoundError: Could not initialize class TestStackOverflowDuringInit$LongCache"; String cause = "Caused by: java.lang.StackOverflowError"; + // Pre-load, but not initialize, LongCache, else we will + // hit SOE during class loading. + System.out.println("Pre-loading ..."); + Class c = Class.forName("TestStackOverflowDuringInit$LongCache", + false, + TestStackOverflowDuringInit.class.getClassLoader()); try { recurse(); } catch (Throwable ex) { From 3efa93ba1307cedf05609c0c04b2ba986a515f6e Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 22:03:23 +0000 Subject: [PATCH 82/85] 8335588: Fix -Wzero-as-null-pointer-constant warnings in calls to Node ctor Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/addnode.hpp | 4 ++-- src/hotspot/share/opto/convertnode.hpp | 4 ++-- src/hotspot/share/opto/countbitsnode.hpp | 4 ++-- src/hotspot/share/opto/intrinsicnode.hpp | 18 +++++++++--------- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/memnode.hpp | 2 +- src/hotspot/share/opto/movenode.hpp | 2 +- src/hotspot/share/opto/mulnode.hpp | 20 ++++++++++---------- src/hotspot/share/opto/opaquenode.hpp | 2 +- src/hotspot/share/opto/subnode.hpp | 10 +++++----- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index fd044d6eead..8879606954a 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -43,7 +43,7 @@ typedef const Pair ConstAddOperands; class AddNode : public Node { virtual uint hash() const; public: - AddNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + AddNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Add); } @@ -165,7 +165,7 @@ class AddPNode : public Node { Base, // Base oop, for GC purposes Address, // Actually address, derived from base Offset } ; // Offset added to address - AddPNode( Node *base, Node *ptr, Node *off ) : Node(0,base,ptr,off) { + AddPNode( Node *base, Node *ptr, Node *off ) : Node(nullptr,base,ptr,off) { init_class_id(Class_AddP); } virtual int Opcode() const; diff --git a/src/hotspot/share/opto/convertnode.hpp b/src/hotspot/share/opto/convertnode.hpp index cf76f5ab6fd..9438176a9f9 100644 --- a/src/hotspot/share/opto/convertnode.hpp +++ b/src/hotspot/share/opto/convertnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,7 +260,7 @@ class RoundDoubleModeNode: public Node { rmode_floor = 1, rmode_ceil = 2 }; - RoundDoubleModeNode(Node *in1, Node * rmode): Node(0, in1, rmode) {} + RoundDoubleModeNode(Node *in1, Node * rmode): Node(nullptr, in1, rmode) {} static RoundDoubleModeNode* make(PhaseGVN& gvn, Node* arg, RoundDoubleModeNode::RoundingMode rmode); virtual int Opcode() const; virtual const Type *bottom_type() const { return Type::DOUBLE; } diff --git a/src/hotspot/share/opto/countbitsnode.hpp b/src/hotspot/share/opto/countbitsnode.hpp index b0703d33326..410d5129882 100644 --- a/src/hotspot/share/opto/countbitsnode.hpp +++ b/src/hotspot/share/opto/countbitsnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ class PhaseTransform; //---------- CountBitsNode ----------------------------------------------------- class CountBitsNode : public Node { public: - CountBitsNode(Node* in1) : Node(0, in1) {} + CountBitsNode(Node* in1) : Node(nullptr, in1) {} const Type* bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } }; diff --git a/src/hotspot/share/opto/intrinsicnode.hpp b/src/hotspot/share/opto/intrinsicnode.hpp index e8ebad788eb..bfb200b5e96 100644 --- a/src/hotspot/share/opto/intrinsicnode.hpp +++ b/src/hotspot/share/opto/intrinsicnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,7 +239,7 @@ class WhitespaceNode : public Node { //------------------------------CopySign----------------------------------------- class CopySignDNode : public Node { protected: - CopySignDNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + CopySignDNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static CopySignDNode* make(PhaseGVN& gvn, Node* in1, Node* in2); virtual int Opcode() const; @@ -249,7 +249,7 @@ class CopySignDNode : public Node { class CopySignFNode : public Node { public: - CopySignFNode(Node* in1, Node* in2) : Node(0, in1, in2) {} + CopySignFNode(Node* in1, Node* in2) : Node(nullptr, in1, in2) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeLong::FLOAT; } virtual uint ideal_reg() const { return Op_RegF; } @@ -258,7 +258,7 @@ class CopySignFNode : public Node { //------------------------------Signum------------------------------------------- class SignumDNode : public Node { protected: - SignumDNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + SignumDNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static SignumDNode* make(PhaseGVN& gvn, Node* in); virtual int Opcode() const; @@ -268,7 +268,7 @@ class SignumDNode : public Node { class SignumFNode : public Node { protected: - SignumFNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + SignumFNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static SignumFNode* make(PhaseGVN& gvn, Node* in); virtual int Opcode() const; @@ -306,7 +306,7 @@ class ExpandBitsNode : public TypeNode { //---------- IsInfiniteFNode ----------------------------------------------------- class IsInfiniteFNode : public Node { public: - IsInfiniteFNode(Node* in1) : Node(0, in1) {} + IsInfiniteFNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -315,7 +315,7 @@ class IsInfiniteFNode : public Node { //---------- IsInfiniteDNode ----------------------------------------------------- class IsInfiniteDNode : public Node { public: - IsInfiniteDNode(Node* in1) : Node(0, in1) {} + IsInfiniteDNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -324,7 +324,7 @@ class IsInfiniteDNode : public Node { //---------- IsFiniteFNode ----------------------------------------------------- class IsFiniteFNode : public Node { public: - IsFiniteFNode(Node* in1) : Node(0, in1) {} + IsFiniteFNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -333,7 +333,7 @@ class IsFiniteFNode : public Node { //---------- IsFiniteDNode ----------------------------------------------------- class IsFiniteDNode : public Node { public: - IsFiniteDNode(Node* in1) : Node(0, in1) {} + IsFiniteDNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 448c29b6976..7d78bf5021c 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -514,7 +514,7 @@ inline jlong BaseCountedLoopNode::stride_con() const { class LoopLimitNode : public Node { enum { Init=1, Limit=2, Stride=3 }; public: - LoopLimitNode( Compile* C, Node *init, Node *limit, Node *stride ) : Node(0,init,limit,stride) { + LoopLimitNode( Compile* C, Node *init, Node *limit, Node *stride ) : Node(nullptr,init,limit,stride) { // Put it on the Macro nodes list to optimize during macro nodes expansion. init_flags(Flag_is_macro); C->add_macro_node(this); diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index e0f5a437413..1b65585f1a0 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1681,7 +1681,7 @@ class CacheWBPostSyncNode : public Node { // Allocation prefetch which may fault, TLAB size have to be adjusted. class PrefetchAllocationNode : public Node { public: - PrefetchAllocationNode(Node *mem, Node *adr) : Node(0,mem,adr) {} + PrefetchAllocationNode(Node *mem, Node *adr) : Node(nullptr,mem,adr) {} virtual int Opcode() const; virtual uint ideal_reg() const { return NotAMachineReg; } virtual uint match_edge(uint idx) const { return idx==2; } diff --git a/src/hotspot/share/opto/movenode.hpp b/src/hotspot/share/opto/movenode.hpp index ae1e8563da3..02db0c73079 100644 --- a/src/hotspot/share/opto/movenode.hpp +++ b/src/hotspot/share/opto/movenode.hpp @@ -158,7 +158,7 @@ class MoveD2LNode : public MoveNode { // (CMove (Binary bol cmp) (Binary src1 src2)) class BinaryNode : public Node { public: - BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } + BinaryNode( Node *n1, Node *n2 ) : Node(nullptr,n1,n2) { } virtual int Opcode() const; virtual uint ideal_reg() const { return 0; } }; diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index 10ef442299d..4c5e3e33248 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,7 +167,7 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot); // Upper 64 bits of a 64 bit by 64 bit multiply class MulHiLNode : public Node { public: - MulHiLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + MulHiLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual const Type* Value(PhaseGVN* phase) const; const Type *bottom_type() const { return TypeLong::LONG; } @@ -178,7 +178,7 @@ class MulHiLNode : public Node { // Upper 64 bits of a 64 bit by 64 bit unsigned multiply class UMulHiLNode : public Node { public: - UMulHiLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + UMulHiLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual const Type* Value(PhaseGVN* phase) const; const Type *bottom_type() const { return TypeLong::LONG; } @@ -291,7 +291,7 @@ class RotateRightNode : public TypeNode { // Signed shift right class RShiftINode : public Node { public: - RShiftINode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + RShiftINode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -304,7 +304,7 @@ class RShiftINode : public Node { // Signed shift right class RShiftLNode : public Node { public: - RShiftLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + RShiftLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual const Type* Value(PhaseGVN* phase) const; @@ -316,7 +316,7 @@ class RShiftLNode : public Node { // Logical shift right class URShiftBNode : public Node { public: - URShiftBNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + URShiftBNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { ShouldNotReachHere(); // only vector variant is used } virtual int Opcode() const; @@ -326,7 +326,7 @@ class URShiftBNode : public Node { // Logical shift right class URShiftSNode : public Node { public: - URShiftSNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + URShiftSNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { ShouldNotReachHere(); // only vector variant is used } virtual int Opcode() const; @@ -336,7 +336,7 @@ class URShiftSNode : public Node { // Logical shift right class URShiftINode : public Node { public: - URShiftINode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + URShiftINode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -349,7 +349,7 @@ class URShiftINode : public Node { // Logical shift right class URShiftLNode : public Node { public: - URShiftLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + URShiftLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -396,7 +396,7 @@ class FmaFNode : public FmaNode { class MulAddS2INode : public Node { virtual uint hash() const; public: - MulAddS2INode(Node* in1, Node *in2, Node *in3, Node* in4) : Node(0, in1, in2, in3, in4) {} + MulAddS2INode(Node* in1, Node *in2, Node *in3, Node* in4) : Node(nullptr, in1, in2, in3, in4) {} virtual int Opcode() const; const Type *bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 4617979c2e4..9c775408cc0 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -140,7 +140,7 @@ class ProfileBooleanNode : public Node { virtual uint hash() const ; // { return NO_HASH; } virtual bool cmp( const Node &n ) const; public: - ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(0, n), + ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(nullptr, n), _false_cnt(false_cnt), _true_cnt(true_cnt), _consumed(false), _delay_removal(true) {} uint false_count() const { return _false_cnt; } diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index f424e258db2..a0c052645c6 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ // are compressed into -1, and all positive answers compressed to 1. class SubNode : public Node { public: - SubNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + SubNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Sub); } @@ -363,7 +363,7 @@ class BoolNode : public Node { // for finding this pattern in the graph. class AbsNode : public Node { public: - AbsNode( Node *value ) : Node(0,value) {} + AbsNode( Node *value ) : Node(nullptr,value) {} virtual Node* Identity(PhaseGVN* phase); virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; @@ -420,7 +420,7 @@ class AbsDNode : public AbsNode { // If p < q, return -1 else return 0. Nice for flow-free idioms. class CmpLTMaskNode : public Node { public: - CmpLTMaskNode( Node *p, Node *q ) : Node(0, p, q) {} + CmpLTMaskNode( Node *p, Node *q ) : Node(nullptr, p, q) {} virtual int Opcode() const; const Type *bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } @@ -430,7 +430,7 @@ class CmpLTMaskNode : public Node { //------------------------------NegNode---------------------------------------- class NegNode : public Node { public: - NegNode(Node* in1) : Node(0, in1) { + NegNode(Node* in1) : Node(nullptr, in1) { init_class_id(Class_Neg); } }; From e01626cf09850f7b0af33cdb905ca8992266fe5b Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 4 Jul 2024 04:18:31 +0000 Subject: [PATCH 83/85] 8335655: ProblemList serviceability/dcmd/vm tests failing after JDK-8322475 Reviewed-by: mikael --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 3 +++ test/hotspot/jtreg/ProblemList-zgc.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index db8182641ac..bdeed9947c5 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -114,4 +114,7 @@ serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic- serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all +serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all +serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 1afe56c99f8..892c980b069 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -45,4 +45,7 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all +serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all +serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 From 7b894bc4afa96bc04f0d58042f69becadb573e20 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 4 Jul 2024 05:44:44 +0000 Subject: [PATCH 84/85] 8332786: When dumping static CDS archives, explicitly assert that we don't use a CDS archive Reviewed-by: iklam, dholmes --- src/hotspot/share/cds/metaspaceShared.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index a5061fef567..4d978a7ad88 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -510,6 +510,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { } void VM_PopulateDumpSharedSpace::doit() { + guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); + DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); FileMapInfo::check_nonempty_dir_in_shared_path_table(); From 38a578d547f39c3637d97f5e0242f4a69f3bbb31 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 4 Jul 2024 06:20:03 +0000 Subject: [PATCH 85/85] 8334738: os::print_hex_dump should optionally print ASCII Reviewed-by: dholmes, sgehwolf --- .../windows_aarch64/os_windows_aarch64.cpp | 4 +- src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 89 ++++++++---- src/hotspot/share/runtime/os.hpp | 8 +- .../share/utilities/globalDefinitions.hpp | 1 + src/hotspot/share/utilities/ostream.hpp | 1 + test/hotspot/gtest/runtime/test_os.cpp | 131 ++++++++++-------- 7 files changed, 144 insertions(+), 92 deletions(-) diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp index 78e98609b6b..722c3c8dd60 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, Microsoft Corporation. All rights reserved. - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,7 +219,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // this at the end, and hope for the best. address pc = (address)uc->Pc; st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char), /* print_ascii=*/false); st->cr(); } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index a87a3ff042d..fdbb6605c13 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1273,7 +1273,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { // longs and doubles will be split into two words. unitsize = sizeof(narrowOop); } - os::print_hex_dump(&lsh, base, top, unitsize, 32, requested_base); + os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); } } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 97bf33fbaaa..d141ee24426 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -938,56 +938,73 @@ bool os::print_function_and_library_name(outputStream* st, return have_function_name || have_library_name; } -ATTRIBUTE_NO_ASAN static bool read_safely_from(intptr_t* p, intptr_t* result) { - const intptr_t errval = 0x1717; - intptr_t i = SafeFetchN(p, errval); +ATTRIBUTE_NO_ASAN static bool read_safely_from(const uintptr_t* p, uintptr_t* result) { + DEBUG_ONLY(*result = 0xAAAA;) + const uintptr_t errval = 0x1717; + uintptr_t i = (uintptr_t)SafeFetchN((intptr_t*)p, errval); if (i == errval) { - i = SafeFetchN(p, ~errval); + i = (uintptr_t)SafeFetchN((intptr_t*)p, ~errval); if (i == ~errval) { return false; } } - (*result) = i; + (*result) = (uintptr_t)i; return true; } -static void print_hex_location(outputStream* st, address p, int unitsize) { +// Helper for os::print_hex_dump +static void print_ascii_form(stringStream& ascii_form, uint64_t value, int unitsize) { + union { + uint64_t v; + uint8_t c[sizeof(v)]; + } u = { value }; + for (int i = 0; i < unitsize; i++) { + const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - 1 - i); + const uint8_t c = u.c[idx]; + ascii_form.put(isprint(c) && isascii(c) ? c : '.'); + } +} + +// Helper for os::print_hex_dump +static void print_hex_location(outputStream* st, const_address p, int unitsize, stringStream& ascii_form) { assert(is_aligned(p, unitsize), "Unaligned"); - address pa = align_down(p, sizeof(intptr_t)); + const uintptr_t* pa = (const uintptr_t*) align_down(p, sizeof(intptr_t)); #ifndef _LP64 // Special handling for printing qwords on 32-bit platforms if (unitsize == 8) { - intptr_t i1, i2; - if (read_safely_from((intptr_t*)pa, &i1) && - read_safely_from((intptr_t*)pa + 1, &i2)) { + uintptr_t i1 = 0, i2 = 0; + if (read_safely_from(pa, &i1) && + read_safely_from(pa + 1, &i2)) { const uint64_t value = LITTLE_ENDIAN_ONLY((((uint64_t)i2) << 32) | i1) BIG_ENDIAN_ONLY((((uint64_t)i1) << 32) | i2); st->print("%016" FORMAT64_MODIFIER "x", value); + print_ascii_form(ascii_form, value, unitsize); } else { st->print_raw("????????????????"); } return; } #endif // 32-bit, qwords - intptr_t i = 0; - if (read_safely_from((intptr_t*)pa, &i)) { + uintptr_t i = 0; + if (read_safely_from(pa, &i)) { // bytes: CA FE BA BE DE AD C0 DE // bytoff: 0 1 2 3 4 5 6 7 // LE bits: 0 8 16 24 32 40 48 56 // BE bits: 56 48 40 32 24 16 8 0 - const int offset = (int)(p - (address)pa); + const int offset = (int)(p - (const_address)pa); const int bitoffset = LITTLE_ENDIAN_ONLY(offset * BitsPerByte) BIG_ENDIAN_ONLY((int)((sizeof(intptr_t) - unitsize - offset) * BitsPerByte)); const int bitfieldsize = unitsize * BitsPerByte; - intptr_t value = bitfield(i, bitoffset, bitfieldsize); + uintptr_t value = bitfield(i, bitoffset, bitfieldsize); switch (unitsize) { case 1: st->print("%02x", (u1)value); break; case 2: st->print("%04x", (u2)value); break; case 4: st->print("%08x", (u4)value); break; case 8: st->print("%016" FORMAT64_MODIFIER "x", (u8)value); break; } + print_ascii_form(ascii_form, value, unitsize); } else { switch (unitsize) { case 1: st->print_raw("??"); break; @@ -998,36 +1015,56 @@ static void print_hex_location(outputStream* st, address p, int unitsize) { } } -void os::print_hex_dump(outputStream* st, address start, address end, int unitsize, - int bytes_per_line, address logical_start) { +void os::print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, + bool print_ascii, int bytes_per_line, const_address logical_start) { + constexpr int max_bytes_per_line = 64; assert(unitsize == 1 || unitsize == 2 || unitsize == 4 || unitsize == 8, "just checking"); + assert(bytes_per_line > 0 && bytes_per_line <= max_bytes_per_line && + is_power_of_2(bytes_per_line), "invalid bytes_per_line"); start = align_down(start, unitsize); logical_start = align_down(logical_start, unitsize); bytes_per_line = align_up(bytes_per_line, 8); int cols = 0; - int cols_per_line = bytes_per_line / unitsize; + const int cols_per_line = bytes_per_line / unitsize; - address p = start; - address logical_p = logical_start; + const_address p = start; + const_address logical_p = logical_start; + + stringStream ascii_form; // Print out the addresses as if we were starting from logical_start. - st->print(PTR_FORMAT ": ", p2i(logical_p)); while (p < end) { - print_hex_location(st, p, unitsize); + if (cols == 0) { + st->print(PTR_FORMAT ": ", p2i(logical_p)); + } + print_hex_location(st, p, unitsize, ascii_form); p += unitsize; logical_p += unitsize; cols++; - if (cols >= cols_per_line && p < end) { - cols = 0; + if (cols >= cols_per_line) { + if (print_ascii && !ascii_form.is_empty()) { + st->print(" %s", ascii_form.base()); + } + ascii_form.reset(); st->cr(); - st->print(PTR_FORMAT ": ", p2i(logical_p)); + cols = 0; } else { st->print(" "); } } - st->cr(); + + if (cols > 0) { // did not print a full line + if (print_ascii) { + // indent last ascii part to match that of full lines + const int size_of_printed_unit = unitsize * 2; + const int space_left = (cols_per_line - cols) * (size_of_printed_unit + 1); + st->sp(space_left); + st->print(" %s", ascii_form.base()); + } + st->cr(); + } } void os::print_dhm(outputStream* st, const char* startStr, long sec) { @@ -1045,7 +1082,7 @@ void os::print_tos(outputStream* st, address sp) { void os::print_instructions(outputStream* st, address pc, int unitsize) { st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); - print_hex_dump(st, pc - 256, pc + 256, unitsize); + print_hex_dump(st, pc - 256, pc + 256, unitsize, /* print_ascii=*/false); } void os::print_environment_variables(outputStream* st, const char** env_list) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index f3f44ddb2e6..af8eb8c8b9a 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -856,10 +856,10 @@ class os: AllStatic { // return current frame. pc() and sp() are set to null on failure. static frame current_frame(); - static void print_hex_dump(outputStream* st, address start, address end, int unitsize, - int bytes_per_line, address logical_start); - static void print_hex_dump(outputStream* st, address start, address end, int unitsize) { - print_hex_dump(st, start, end, unitsize, /*bytes_per_line=*/16, /*logical_start=*/start); + static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii, + int bytes_per_line, const_address logical_start); + static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii = true) { + print_hex_dump(st, start, end, unitsize, print_ascii, /*bytes_per_line=*/16, /*logical_start=*/start); } // returns a string to describe the exception/signal; diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index a15a4de3e93..74817a35e77 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -455,6 +455,7 @@ typedef unsigned int uint; NEEDS_CLEANUP typedef signed char s_char; typedef unsigned char u_char; typedef u_char* address; +typedef const u_char* const_address; // Pointer subtraction. // The idea here is to avoid ptrdiff_t, which is signed and so doesn't have diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index beb02309d3f..9faaf32fb6b 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -267,6 +267,7 @@ class stringStream : public outputStream { return _buffer; }; void reset(); + bool is_empty() const { return _buffer[0] == '\0'; } // Copy to a resource, or C-heap, array as requested char* as_string(bool c_heap = false) const; }; diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 55d30349ee5..654c2c60673 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -167,82 +167,95 @@ TEST_VM_ASSERT_MSG(os, page_size_for_region_with_zero_min_pages, } #endif -static void do_test_print_hex_dump(address addr, size_t len, int unitsize, const char* expected) { - char buf[256]; +#ifndef AIX +// Test relies on the ability to protect memory allocated with os::reserve_memory. AIX may not be able +// to do that (mprotect won't work on System V shm). +static void do_test_print_hex_dump(const_address from, const_address to, int unitsize, int bytes_per_line, + const_address logical_start, const char* expected) { + char buf[2048]; buf[0] = '\0'; stringStream ss(buf, sizeof(buf)); - os::print_hex_dump(&ss, addr, addr + len, unitsize); - // tty->print_cr("expected: %s", expected); - // tty->print_cr("result: %s", buf); - EXPECT_THAT(buf, HasSubstr(expected)); + os::print_hex_dump(&ss, from, to, unitsize, /* print_ascii=*/true, bytes_per_line, logical_start); + EXPECT_STREQ(buf, expected); } TEST_VM(os, test_print_hex_dump) { - const char* pattern [4] = { -#ifdef VM_LITTLE_ENDIAN - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", - "0100 0302 0504 0706 0908 0b0a 0d0c 0f0e", - "03020100 07060504 0b0a0908 0f0e0d0c", - "0706050403020100 0f0e0d0c0b0a0908" + +#ifdef _LP64 +#define ADDRESS1 "0x0000aaaaaaaaaa00" +#define ADDRESS2 "0x0000aaaaaaaaaa20" +#define ADDRESS3 "0x0000aaaaaaaaaa40" #else - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", - "0001 0203 0405 0607 0809 0a0b 0c0d 0e0f", - "00010203 04050607 08090a0b 0c0d0e0f", - "0001020304050607 08090a0b0c0d0e0f" +#define ADDRESS1 "0xaaaaaa00" +#define ADDRESS2 "0xaaaaaa20" +#define ADDRESS3 "0xaaaaaa40" #endif - }; - const char* pattern_not_readable [4] = { - "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??", - "???? ???? ???? ???? ???? ???? ???? ????", - "???????? ???????? ???????? ????????", - "???????????????? ????????????????" - }; +#define ASCII_1 "....#.jdk/internal/loader/Native" +#define ASCII_2 "Libraries......." - // On AIX, zero page is readable. - address unreadable = -#ifdef AIX - (address) 0xFFFFFFFFFFFF0000ULL; +#define PAT_1 ADDRESS1 ": ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??\n" \ + ADDRESS2 ": ff ff e0 dc 23 00 6a 64 6b 2f 69 6e 74 65 72 6e 61 6c 2f 6c 6f 61 64 65 72 2f 4e 61 74 69 76 65 " ASCII_1 "\n" \ + ADDRESS3 ": 4c 69 62 72 61 72 69 65 73 00 00 00 00 00 00 00 " ASCII_2 "\n" + +#ifdef VM_LITTLE_ENDIAN +#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \ + ADDRESS2 ": ffff dce0 0023 646a 2f6b 6e69 6574 6e72 6c61 6c2f 616f 6564 2f72 614e 6974 6576 " ASCII_1 "\n" \ + ADDRESS3 ": 694c 7262 7261 6569 0073 0000 0000 0000 " ASCII_2 "\n" + +#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \ + ADDRESS2 ": dce0ffff 646a0023 6e692f6b 6e726574 6c2f6c61 6564616f 614e2f72 65766974 " ASCII_1 "\n" \ + ADDRESS3 ": 7262694c 65697261 00000073 00000000 " ASCII_2 "\n" + +#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \ + ADDRESS2 ": 646a0023dce0ffff 6e7265746e692f6b 6564616f6c2f6c61 65766974614e2f72 " ASCII_1 "\n" \ + ADDRESS3 ": 656972617262694c 0000000000000073 " ASCII_2 "\n" #else - (address) 0 -#endif - ; +#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \ + ADDRESS2 ": ffff e0dc 2300 6a64 6b2f 696e 7465 726e 616c 2f6c 6f61 6465 722f 4e61 7469 7665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c69 6272 6172 6965 7300 0000 0000 0000 " ASCII_2 "\n" - ResourceMark rm; - char buf[64]; - stringStream ss(buf, sizeof(buf)); - outputStream* out = &ss; -// outputStream* out = tty; // enable for printout - - // Test dumping unreadable memory - // Exclude test for Windows for now, since it needs SEH handling to work which cannot be - // guaranteed when we call directly into VM code. (see JDK-8220220) -#ifndef _WIN32 - do_test_print_hex_dump(unreadable, 100, 1, pattern_not_readable[0]); - do_test_print_hex_dump(unreadable, 100, 2, pattern_not_readable[1]); - do_test_print_hex_dump(unreadable, 100, 4, pattern_not_readable[2]); - do_test_print_hex_dump(unreadable, 100, 8, pattern_not_readable[3]); +#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \ + ADDRESS2 ": ffffe0dc 23006a64 6b2f696e 7465726e 616c2f6c 6f616465 722f4e61 74697665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c696272 61726965 73000000 00000000 " ASCII_2 "\n" + +#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \ + ADDRESS2 ": ffffe0dc23006a64 6b2f696e7465726e 616c2f6c6f616465 722f4e6174697665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c69627261726965 7300000000000000 " ASCII_2 "\n" #endif - // Test dumping readable memory - address arr = (address)os::malloc(100, mtInternal); - for (u1 c = 0; c < 100; c++) { - arr[c] = c; - } + constexpr uint8_t bytes[] = { + 0xff, 0xff, 0xe0, 0xdc, 0x23, 0x00, 0x6a, 0x64, 0x6b, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // two pages, first one protected. + const size_t ps = os::vm_page_size(); + char* two_pages = os::reserve_memory(ps * 2, false, mtTest); + os::commit_memory(two_pages, ps * 2, false); + os::protect_memory(two_pages, ps, os::MEM_PROT_NONE, true); + + memcpy(two_pages + ps, bytes, sizeof(bytes)); + + // print + const const_address from = (const_address) two_pages + ps - 32; + const const_address to = (const_address) from + 32 + sizeof(bytes); + const const_address logical_start = (const_address) LP64_ONLY(0xAAAAAAAAAA00ULL) NOT_LP64(0xAAAAAA00ULL); - // properly aligned - do_test_print_hex_dump(arr, 100, 1, pattern[0]); - do_test_print_hex_dump(arr, 100, 2, pattern[1]); - do_test_print_hex_dump(arr, 100, 4, pattern[2]); - do_test_print_hex_dump(arr, 100, 8, pattern[3]); + do_test_print_hex_dump(from, to, 1, 32, logical_start, PAT_1); + do_test_print_hex_dump(from, to, 2, 32, logical_start, PAT_2); + do_test_print_hex_dump(from, to, 4, 32, logical_start, PAT_4); + do_test_print_hex_dump(from, to, 8, 32, logical_start, PAT_8); - // Not properly aligned. Should automatically down-align by unitsize - do_test_print_hex_dump(arr + 1, 100, 2, pattern[1]); - do_test_print_hex_dump(arr + 1, 100, 4, pattern[2]); - do_test_print_hex_dump(arr + 1, 100, 8, pattern[3]); + // unaligned printing, should align to next lower unitsize + do_test_print_hex_dump(from + 1, to, 2, 32, logical_start, PAT_2); + do_test_print_hex_dump(from + 1, to, 4, 32, logical_start, PAT_4); + do_test_print_hex_dump(from + 1, to, 8, 32, logical_start, PAT_8); - os::free(arr); + os::release_memory(two_pages, ps * 2); } +#endif // not AIX ////////////////////////////////////////////////////////////////////////////// // Test os::vsnprintf and friends.